스토리 홈

인터뷰

피드

뉴스

조회수 593

우리는 모두 외롭다

세상은 외로움을 회피하는방향으로 움직인다"왕따가 왜 무서운 건지 아니?""인간은 혼자일 때가 가장 두렵기 때문이야"사람들이 스마트폰과 SNS에 집착하는것은 누군가의 소식이 궁금해서도 아니고 재미있는 것을 찾기 위해서도 아니다. 외로움이 두렵기 때문이다. 외롭게 보이고 싶지 않기 때문이다.어딘가 소속되고 싶어하는 마음도, 누군가와 사랑하고 싶은 욕망도 그 처절한 외로움을 회피하고 싶어하기 때문이다.사랑은 세상에 나를 이해해주는 누군가가 존재한다는 위안감 때문에 가치가 있는 것이다.남들과 다른 것을 두려워하고, 어딘가 울타리를 벗어난 것에 불안함을 느끼는 것도 그렇게 함으로써 무리에서 벗어난 느낌을 무서워하기 때문이다.공유 경제의 현상으로 공간을 공유하고, 커뮤니티를 강화하는 것도 궁극적으로는 점차 핵가족화 되어가는 사회에서 나 혼자 남겨지는 것에 대한 반대급부 때문이다.모든 현상의 이면에는외로움에 대한 두려움이 숨어있다앞으로는 개인의 전문성만으로도 사회 생활이 가능해지는 1인 기업, 프리랜서, 원격 업무들이 늘어남에 따라 점차 외로움을 벗어나게 해주는 산업이 발달할 수 밖에 없다.애완동물 산업이 엄청난 속도로 커지고 있다는 것과 소규모 모임들, 데이트 만남 서비스가 확대 되어가는 것도 이것을 입증하는 현상들이다.이미 세상은 1인 가구가 보편적인 가정 형태의 하나인 시대가 되었다. 노인뿐만 아니라 비혼의 성인들, 그리고 결혼 생활을 중단한 많은 이들이 곳곳에 1인 가구를 이루고 있다. 인류 역사상 유래 없는 현상이다. 한번도 겪어보지 않은 일들을 마주하고 있기 때문에 사회 시스템은 아직 이 현상을 어떻게 대처해야 할지 준비가 되어있지 않다.그래서 뭐?그렇다.그래서 어쩌라구에 대한 답을 찾아야 한다.스마트폰은 외롭고 고립된 인간에게 무한한 연결을 가능하게 해준 빛이 되었던 것이다. 장소와 시간에 상관없이 누군가와 연결되어 있다는 심리적 소속감에 거리를 거닐면서도 밤에 잠을 이루기 전에도, 사회에서 인정받지 못한 스스로를 가상의 게임 공간에서 강인한 캐릭터로 위안 받는 세상을 이해해야 한다.지하철에서 하루 일과에 찌든 중년의 아주머니조차 줄맞춰 터트리는 모바일 게임에 빠질 수밖에 이유는 허무한 일상과 혼자라는 두려움을 벗어나는 간편한 탈출구이기 때문이다. 세상이 어떤 방향으로진화할 것인지에 대한 해답세상이 빠르게 변하더라도 인간의 본질적 욕망은 변하지 않는다. IT기술을 개발해야 하는 기업이나, 소셜 서비스를 발굴하는 스타트업들이나, 제도를 마련해야하고 정책을 펼치는 정치인들 모두 우리가 한번도 경험해보지 못한 형태의 새로운 고독을 직면해야할 인간의 문제를 심각하게 고민해야 할 것이다.모든 것의 중심에는 인간이 있어야 한다.명백한 것은 행복은 외로움의 반대 방향일 것이라는 것이다.외롭지 말자.
조회수 1251

깃발 올려, Git Effect!

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

경영자와 관리자의 차이

경영자와 관리자, 이 두 역할에는 어떤 차이점이 있을까?  모두 다 같은 뜻인지? 예전에 그런 생각을 했었다.  흔히, 최고경영자는 CEO, 최고운영책임자는COO라고 한다.  지난 여름, 홍콩 헤지펀드사에서 인턴을 했을 때 내가 좋아했던 상사 한 분이 계셨는데 그분이 COO이셨다.  그때부터 COO라는 직책에 관심을 갖게 되었다.사전적인 의미는 다음과 같다.CEO: Chief Executive Officer 약자로 회사의 최고경영운영자이다.  CEO는 나름의 경영 철학을 갖고 회사의 장기적인 경영전략을 수립하고 이러한 전략을 완수하는데 필요한 최종의 의사결정을 하는 사람이다.COO: Chief Operating Officer 는 기업 내부의 사업을 총괄하는 책임자, 최고운영책임자를 의미한다.2000년도서부터 미국 실리콘밸리에서 처음 포지션이 생겨나기 시작해 세계적으로 파급된 직책으로, 기업 내의 사업을 총괄하는 책임자를 말한다.CEO는 기업 전반적인 목표, 비전과 전략 방향 등을 확립하며 기업의 모든 활동을 어떻게 이끌어나갈지 결정하고 이끌어나가는 사람이다. 그렇기 때문에 기업의 ‘대표’라고 말할 수 있고, 작은 것에 연연하기보다는 거시적이고 장기적인 관점에서, CEO의 철학에 따라, 그 기업이 어떻게 운영되는지가 결정된다고 볼 수 있다.  또한, CEO는 주로 외부적 활동을 많이 한다.COO는 기업의 구체적인 운영과 관리에 대한 업무를 전담하는 직책이다. 대개의 경우에 CEO가 사장이라면 COO는 수석 부사장 등이 맡는 경우가 많다고 한다.  주로 대기업에서 이런 형식을 채택하고 벤처기업에서는 CEO와 COO 를 구분하지 않고 두 직책을 CEO가 전담하는 경우가 많지만 기업이 성장하면서 자연스럽게 내부와 외부 활동이 나뉘어지며, 그러면서 자연스럽게 두 역할 또한 구분된다.COO는 CEO를 보조하며 전체적인 기업의 구체적인 운영과 관리에 대한 업무를 담당한다. 그렇기 때문에 CEO보다는 기업 내부의 전반적인 상황과 운영에 대한 노하우가 더 요구되는 직책이다.e.g. 고인이 된 잡스가 작년 초까지만 해도 애플의 최고경영자였으며 (현재 애플 CEO가 된) 팀쿡은 당시 COO였다.   잡스가 (신제품 발표 등)의 대외적인 활동과 애플의 큰 그림을 그리는 역할을 맡았다면, 팀쿡은 애플 회사 자체의 내부 경영과 조직관리에 집중했다.하지만 COO만이 CEO를 보조하는 것은 아니고, 주로 규모가 큰 기업에서는 CEO와 COO뿐만 아니라 CFO(Chief Financial Officer), CIO(Chief Information Officer), CTO(Chief Technology Officer), CSO(Chief Security Officer), CMO(Chief Marketing Officer), CCO(Chief Compliance Officer), CRO(Chief Risk Officer), CBO(Chief Brand Officer) 등등 기업의 영업 활동과 사업분야마다 각각 최고책임자들이 있다. 하지만 이런 업무들을 전체적으로 총괄하고 감독하며 관리하는 직책이 CEO와 COO라고 보면 될 것 같다.CEO 와 COO 의 차이점은 Accenture가 발행한 article에서 사례로 보다 자세히 나와 있다. 액센츄어는 COO가 CEO가 되기 위한 훈련생이라고 정의했다.Accenture_Outlook_Mastering_move_from_COO_to_CEO.pdf.나는 CEO 보다 COO, 그리고 경영자보다는 관리자의 역할에 더 많이 관심이 간다.  회사가 성장하기 위해선 올바른 방향을 제시하고 배를 모는 선장의 역할도 중요하지만, 선원들이 자기가 맡은 역할을 명확히 하고 일할 수 있게 조성해주고 선원 관리를 잘 하는 역할도 무시할 수가 없기 때문이다.  서비스업이든, 제조업이든, 뭐든 간에 결국은 사람이 기업을 만들어간다.  그 사람관리가 제대로 되지 않으면 배가 산으로 간다.  인재 한 명이 기업을 성장시키고 또 못난 직원 한 명이 기업을 망하게 한다.  최근 UBS 에서 또 한번의 거대 금융 사기가 벌어졌다.  UBS 트레이더가 무려 2억달러 (2조원)의 회사 돈을 한방에 날려먹었다.기업을 살리고 마는 건 결국 ‘사람’이다.  넷뱅에 참여하면서 사람관리의 어려움, 복잡함, 중요성을 절감했다. 그래서 복학하고 이번 학기에 인사관리라는 과목을 수강했다. 무엇보다, 사람관리, 직원관리에 대한 전문적인 지식을 갖춰야 할 필요성을 느꼈다.  직원관리와 사내문화가 체계화가 돼야 어떤 새로운 직원이 들어오고 또 기존 직원이 나가도 뼈대가 흔들리지 않고 꿈쩍도 안 할 수 있다.  나는 ‘신생 기업’의 성장과 발전에 있어서 HR의 시스템화를 가장 중요하게 여기고 있다.내가 영국으로 떠나기 2주 전부터, 집중했던 것이 팀원 교육이었다.  대표님의 지시하에 교육자료 만들기에 주력하였고 바쁘신 대표님을 대신해 사무실에서 내근하는 팀원들에게 직접 경영 방침, 계획 내용, 취지를 전달하는 역할을 맡았다.  이를 통해, 현장관리의 중요성도 깨닫게 되었는데, 관리자가 벤처기업 또는 중소기업을 성장시키려면 어떤 식으로 직원관리와 성과관리, 분석을 해야 하는지에 대해 관련 저널을 찾아 읽어봐야겠다.  학교에서 곧 있으면 직원들의 performance 관리와 분석, 평가, 보상에 대해 수업을 들을 예정인데, 잘 들었다가 넷뱅에 적용할 수 있게 대표님께 제안할 생각이다.#넷뱅 #팀빌딩 #CEO #COO #인사이트
조회수 1058

34살 살아보면서 느낀것들

※ 본 글은 '26 Things I've Learned in 26 Years' 글에서 모티브를 얻어 작성되었습니다.아직 인생의 반의 반도 살아보지 않았지만, 지금까지 살아보면서 느낀걸 정리해 보는건 나름 의미가 있다고 생각한다. 미디엄에서 본 글에서 모티브를 얻어서 지금까지 한국나이로 34살 살아오면서 느낀 점들을 나도 한번 정리해 보았다. 물론 '느낀점'이기 때문에 이게 옳다는것도 아니고 더 살아가면서 생각을 바꿀 것들도 제법 많이 존재할 것이다. 아울러 혹시 다른 사람들도 본인의 느낀점들을 정리해서 서로 연결해서 공유해 보는것도 재밌을 것 같다.1. 부모님이 살아간 방식대로 살아가면 큰일난다80년대생은 나름 삶의 패러다임이 현격하게 바뀌는 두 지점의 중간에 끼어있는 세대이다. 부모세대가 살아온 성공방정식과 우리보다 어린 세대의 그것은 A부터 Z까지 다 다를거고, 인공지능으로 변화될 인간의 역할세계의 범주 역시 부모세대는 살짝 비켜가지만 80년대생 부터는 직격탄을 맞기 시작하는 세대이다. 이런 상황에서 공부 열심히해서 좋은 대학가고 대기업에서 승승장구하는 부모님이 바라는 삶대로 살아가다간 2020년대에 어떻게 될지 장담할 수 없다. 이 부분에 대해서는 추후 별도의 글로 나름의 의견을 풀어볼 예정이다.2. 목적의식 없는 인내(忍耐)는 인내가 아니라 순응하는거다우리는 어렸을때 부터 항상 '인내하는 사람'의 미학에 대해 배워왔다. 호랑이와는 다르게 21일동안 쑥과 마늘만 먹고 인내한 곰이 드디어 인간이 된 이야기, 2000번의 실패 끝에 전구를 발명한 토마스 에디슨 이야기 (사실인지는 모르겠지만..) 등등 쓰디쓴 인내의 시간을 견디면 성공의 달콤한 열매를 얻을 수 있을 거라는 가르침이다. 하지만 저런 인내의 가르침 이면에는 사실 순응하는 인간을 길러내기 위한 무시무시한 의도가 숨겨져 있음을 그 당시에는 깨닫지 못했다. 생활기록부에 적혀있는 문구들 중 흔하게 보는 표현이 있는데 바로 '이 학생은 인내심이 강하다'라는 것이다. 그 학생이 왜 인내심이 강하냐고 물어보면 '이 학생은 뭘 하든지 불평이 없고, 선생님이 시키는대로 가르침을 잘 따르고, 심지어 단체기합을 받아도 이 학생은 잘 참아내는 학생입니다'라고 대답한다. 이 사회는 윗 사람의 지시에 불평 불만 없이 잘 따르는 사람을 '인내심 강한 사람'이라고 정의내리고 있는 것이다. 내가 '무엇을 위해 인내하는가'에 대한 자각 없이 그냥 참고 견디는건 인내가 아니라 그냥 순응하는거고 내 정신건강만 축내는 행위라고 생각한다.3. 아무리 친한 사람이라도 내가 신경쓰는 정도의 딱 1%정도만 내 일에 신경써준다내 발등에 불 떨어진 일을 남들도 그렇게 여겨줄거라 생각하다간 큰코다친다. 스타트업하면서 개인적으로 많이 느낀 점이다. 나름 내 생각에서는 이런거 도와주는거 쉬운일이고 나한테는 매우 급한 일이니까 친구라면 당연히 도와주겠지... 하고 기대하는것 만큼 위험한 발상이 없다는 것이다. 물론 개중에 잘 도와주는 사람이 있긴 있다. 이건 그 사람이 정말 대단한 특이케이스인거지 도와주지 않는 남들이 나쁜 친구라고 생각하고 있다가는 주변 친구들 다 떠난다. 그냥 다른 사람들은 내가 생각하는것의 딱 1%정도만 관심있을거라는 마음가짐으로 접근하는게 가장 속 편하다.4. 사소한 일에도 의미부여하는 습관이 중요하다이건 내 바로 전 직장에서 같이 일한 상사로부터 얻은 깨달음이다. 이 분은 모든 사소한 행동에 전부 이유를 갖다붙이는 사람이었는데 그 정도가 얼마나 심했냐면, 같이 밥먹으면서 하는 농담에도 이 농담을 던진 이유가 명확해야 했고, 어떤 메뉴나 식당을 골랐는데 그 이유가 분명하지 않으면 벼락같이 화를내던 분이다. 그 당시에는 '이 사람 이렇게 살아서 얼마나 피곤할까..'하고 생각했었는데 그렇게 같이 2년을 생활하다 보니 확실히 머리속에 논리가 잡히기 시작하고 일의 우선순위를 파악하는 체계가 생기더라. 아무리 사소한 일일지라도 내가 어떤 선택을 해야하는 상황이라면 내가 내린 선택의 이유를 생각해 보는 습관은 제법 유용하다.5. 하루의 모든 순간들이 서로 연결되어 있다이건 요즘 느끼기 시작한 건데, 삶의 매 순간 순간이 마치 유기적으로 연결되어 있다는 느낌이 든다. 내가 만나는 사람들, 내가 지금 하는 일, 내가 밥먹는 이 식당에서 마주친 사람들 등등 단순히 스쳐지나가는 순간일지라도 뭔가 미래의 어떤 순간과 어떤식으로던 엮여 있다고 생각한다. 또한 이 연결되는 방식은 항상 내가 예상하는것과는 전혀 다른 방향으로 작동하는 경우가 많다. 예를들어 내가 프로그래밍 배우려고 코딩을 공부했는데 이게 (내 프로그래밍 능력을 높이기 보다는) 내 디자인스킬을 더 향상시켜주는 방향으로 작용했고, 디자인 스킬이 향상되니까 (디자인 퀄리티가 높아지기 보다는) 디자인 속도가 빨라져서 여유시간이 생겼고, 여유시간이 생기니까 (뭔가 다른 생산적인 일을 하기 보다는) 인터넷 블로그 글들 서핑하고 페북에서 노닥거리는 시간이 늘어났는데 이게 또 내가 블로그활동을 하게 만드는 계기가 되고.. 이런식으로 한가지 사건이 끊임없이 다른 사건들을 유발하면서 이게 내가 의도했던 방향과는 다른 방향으로 계속 흘러나간다는 것이다.6. 회사란 내 인생목표를 위해 활용하는 수단이지 회사 그 자체가 목적이 아니다회사다니다 보면 (나도 한때 그랬었고) 회사 그 자체가 목적인 사람들을 많이 본다. 이 사람들에게는 회사에 나와 일하는게 내가 살아 숨쉬는 이유처럼 보인다. 70년대 개발주도 경제체제에서는 저렇게 살다보면 임원도 달고 해외 주재원도 나가고 뭔가 쟁쟁한 삶을 살아가던 사람이 많았겠지만, 지금 2020년대를 바라보는 우리가 저렇게 살다가는 회사에서 내쳐지고 난 아무것도 할 줄 모르는 사람 되기 십상이다. 회사란 내가 지금 가지고 있는 인생의 어떤 목표를 위해 활용하는 수단 그 이상 그 이하도 아니다.7. 상사란 내 인생목표를 위해 배움을 얻기위한 존재이지 섬기기 위한 존재가 아니다위의 6번과 같은 개념이다. 상사를 무슨 신처럼 섬기면서 회사 다니는 사람들이 있다. 상사란 그저 내 커리어를 먼저 타고 있는 사람으로서 내게 해줄 말이 많고 경험에서 나오는 조언과 가르침을 줄 수 있는 사람이지 내가 섬기기 위해 존재하는 사람이 아니다.8. 배울게 없는 상사는 상사로서 가치가 없다위에서 설명한바와 같다. 상사란 내게 가르침을 줄 수 있어야 의미가 있다. 내가 저 사람에게 배우는게 아무것도 없는데 몇년을 동고동락해서 같이 일해야하는것 만큼 시간낭비가 없다. 인생은 짧고 빠르게 변화한다. 내가 만일 저 상황에 있다면 회사 내에서 다른 사람으로 바꿀 기회를 찾던지, 아니면 이직을 통해서라도 그 상황에서 빠져나와야 한다. 술먹고 정치하는 법 이딴거 배우는거 얘기하는거 아니다.9. 인생목표라는건 하나만 있을 수 없다. 심지어 계속 변한다이것도 최근들어 깨닫기 시작한 거다. 흔히 어른들은 '한번 정한 목표를 뚝심잃지 않고 매진하는 삶의 미학'에 대해 가르친다. 물론 매우 의미있고 멋있는 삶이다. 하지만 지금까지의 삶의 경험으로만 봤을때 저렇게 한번 정한 인생목표에 올인해서 성공하는 케이스는 전체 인구의 5%도 안되는것 같다. 이건 우리세대에서 점점 더 가속화 될게 뻔하다. 3년만 지나도 내가 걷고 있는 이 거리의 모습이 바뀌어가는 세상에서, 우리 회사의 한치 앞의 미래도 불투명한 상황에서 인생 목표라는건 하나만 있을 수 없다고 생각한다. 그리고 이건 계속 그 시대 상황에 맞게 기민하게 변화하고 움직여야 된다고 생각한다.10. '00회사에서 3년' 그 자체는 커리어로서 아무 가치가 없다.이것 역시 최근들어 느낀거다. 우리 이력서를 보면 많은 사람들이 '00회사에서 3년,' '00회사에서 2년' 이런식으로 커리어가 나열되어 있다. 그 밑에 나름 그동안 뭐 했는지를 간단히 요약해서 적는 방식이다. 지금와서 생각해 보면 이렇게 밖에 설명이 안되는 커리어는 아무 가치가 없는것 같다. 그 회사에서 00업무 3년한게 중요한게 아니라 00업무 3년을 통해 내가 앞으로 무엇을 할 수 있는 사람임을 피력할 수 있는게 중요한거 라고 생각한다. 예를들어 내가 00회사에서 영업관리로 3년을 일했다면, 그 일을 통해 내가 최소 '00군의 제품을 00규모의 시장에서 연매출 00정도의 채널로 발굴하는 방법을 아는 사람'이라고 피력하는게 중요하다는 뜻이다.11. 내 능력의 스코프를 모른채 연차만 쌓이는건 커리어에 독이 쌓여나가는것과 같다위의 10번과 같은 맥락이다. 내가 어떤 일을 일구어낼 수 있는 사람인가에 대한 명확한 정의가 서지 않은 채 현재 회사에서 대리, 과장으로 연차만 쌓이고 있는건 커리어에 독이 차곡차곡 쌓여서 점점 시장에서 가치가 없는 사람으로 전락하고 있는것과 같다. 매 순간마다 내가 커리어 시장에 나가면 00분야에 00성과를 낼 능력이 있는 사람이다라는걸 끊임없이 성찰해 보는게 필요하다. 여기서 중요한건, 내가 00시장에서 영업관리를 3년 했으니까 다른 시장에서도 영업관리를 할 수 있을거라..라는 막연한 생각은 아무 가치가 없다. 각 시장마다 생태계가 다르기 때문에 내가 현재 있는 시장에서의 영업관리를 통해 시장 생태계가 어떻게 작동하는지를 알고 있고, 이 생태계가 다른 시장에서는 어떻게 변화하며, 이런 변화에 대해서는 이러이러한 방법으로 관리방법을 변화시킬 수 있다..정도로 아주 구체적으로 스코프를 설명할 수 있는 수준이어야 한다.12. 지금까지 큰 실수없이 무난하게 회사생활 했다면 역시 커리어에 독이 쌓이고 있는거다대기업다니면 가장 많이 듣는 얘기가 있다. '큰 실수 없이 무난하게,' '책임질 일 만들지 말고 그냥' 이런 말들인데, 이런 사고방식으로 회사생활하다가는 커리어에 독이 쌓이기 십상이다. 당신이 만일 회사생활 5년중에 (술자리에서 실수한거 말고) 회사나 조직에 어떤 손해를 끼쳐본 경험이나 매출타격을 입혀본 경험이 없다면 이건 빨간 경고등이 켜져있는 상태와도 같다. 성공은 운으로 얻어지는거 말고는 대부분 실패의 경험으로 얻어지는 경우가 많다. 회사라는 안정된 바운더리 내에서 내돈 아닌 남의 돈 써가면서 일하고 있음에도 실패의 리스크를 져본적이 없다는건 내가 1945 비행기 게임을 하면서 목숨이 2개나 더 있고 폭탄도 2개나 더 쓸 수 있는데 안쓰고 있는 상황과도 같은거다.13. 목적없는 공부는 할 가치가 없다회사다니다 보면 자기개발이라는 미명하에 영어공부, 중국어 공부, 요즘에는 코딩공부까지!! 아무튼 스펙쌓기 목적으로 무작정 공부하는 사람들이 많다. 하지만 내가 지금 하는 이 공부의 목적이 무엇인지도 모른채 그냥 자기개발이 필요하니까 이거 공부해 볼까 하는 마음으로 여가시간, 가족과의 시간 쪼개가면서 공부하는건 아무 가치가 없다. 차라리 그 시간에 내 취미생활을 더 즐기거나 와이프와 데이트를 하는게 100배는 낫다. 목적성 없는 자기개발은 보통 오래 가지도 않을 뿐더러 배우기만 하고 쓰임이 없는 능력은 그냥 연기처럼 사라져 버리는 능력이 되기 때문이다.14. 목적을 가진 취미생활은 할 가치가 없다위의 13번과 유사한 맥락인데, 요즘 취미생활도 무슨 스펙처럼 취급받는 세상에 살고있다 보니 뭔가 스펙쌓기 같은 목적을 가진 취미생활을 하는 사람들이 늘어나고 있다. 취미생활이란 말 그대로 내 여가시간에 즐기는 특정 활동일 뿐이지, 이게 무슨 자기개발처럼 되서는 취미생활이라고 할 수도 없다. 자기개발 목적으로 달려드는 취미생활은 뭔가 공부처럼 받아들이기 때문에 결국 흥미도 떨어지고 시간낭비, 돈낭비만 하게되는 경우가 많다. 차라리 그시간에 열혈강호 60권을 읽어서 스트레스 푸는게 100배는 낫겠다..15. 대행사 직원이 대기업 직원보다 미래에 살아남을 확률이 100배는 높다대기업 다니다 보면 대행사 직원한테 막대하는 사원-대리급 직원들을 발에 치일정도로 보게 된다. 아마도 개발주도시대를 살아온 위의 차장 부장님들 하던 행태를 보고 배워서 그대로 따라하는것 같다. 그런 그들이 깨닫지 못하고 있는건, 저 대행사 직원들은 그 영역에서 자기 손으로 뭔가를 만들어내는 능력이 있는 사람들이고 그 대행사를 부리는 대기업 사원 대리들은 그사람들이 만들어낸 성과를 잘 다듬어서 위에다가 보고하고 지시를 받아오는 사람들이라는 것이다. 직접 자기 손으로 할줄 아는 사람 vs 보고만 하던 사람중 미래에 어떤 사람이 살아남을지는 굳이 설명 안해도 답이 나와있다.16. 영업전선에서 뛰는 사업가가 대기업 직원보다 미래에 살아남을 확률이 100배는 높다위의 15번과 유사한 맥락이다. 특히 대기업의 영업부서에 일하면서 대리점이나 총판을 끼고 일하는 사원 대리급 직원들에게 많이 나타나는 현상인데, 총판 사장님 x무시하면서 뭔가 지 나름의 영업 훈수를 두려는 애들이 있다. 보통은 영업기획팀에서 뽑아준 멋들어진 엑셀 시트를 들이대면서 여기 재고 회전율이 이러이러하고 요 제품군은 영업이익율이 어쩌고 하면서 막 훈수를 두면 (심지어 직원관리 훈수를 두는 사람도 봤다;;) 총판 사장님은 '아이고 00님은 참 똑똑하세요, 모르는게 없으시군요~' 이러면서 비위를 맞춰준다. 장담하는데 대기업과 다이렉트로 영업선을 터놓은 수준의 총판 사장님이라면 영업의 달인급 되는 사람인데, 이런 사람들한테 하나라도 더 배우지는 못할망정 훈수두려고 나불대다가는 나중에 큰코 다친다.17. 내가 만일 '전략'이라는 단어를 많이 쓰고 있는 사람이라면 실제로 뭔가 해본적이 없는 사람일 가능성이 크다.이거 솔직히 나도 그랬다가 요즘 스타트업 하면서 많이 반성하고 있는 부분이다. 내가 만일 기획직에서 일을 하고 있고, 내 보고서에 '무슨무슨 전략' 요런 단어들을 많이 쓰고 있다면 이건 내가 '아는게 별로 없는 사람이요'라고 광고하는것과 같은 뜻이다. 전략이라는건 사실 군대용어이다. 적과 싸우는 상황에서 군대같이 우리조직이 100% 통제 가능하고, 적에대한 정보를 이용해서 적을 찍어누르기 위해 사용하는게 전략이라는 것이다. 당연히 현실세계에서 '전략'이라는 말을 쓸때 보통 많이 나오는 실수가 1/ 전략인데 찍어누를 상대가 없는 상황에서 쓰이고, 2/ 전략이면 우리 회사에서 해당 조직들이 100% 통제 가능한 상황에서 워킹해야 하는 것인데 해당 조직들은 당연히 이게 진행되는지 모르고 있으며, 3/ 전략이라면 적과 시장에 대한 정보가 명확해야 하는건데 그런것도 아닌 그냥 멋드러지게 보이려고 쓰는 단어가 전략처럼 되어버린 것이다. 특히 '마케팅 전략,' 'SNS 전략'같은 단어들은 정말 조심해서 써야하는 단어들이다.18. 삶의 동반자를 만난다는건 인생의 큰 도약이다너무 일얘기만 한것 같아서 삶에 대한 얘기를 꺼내려고 한다. 사람은 결혼 전/후로 사고방식이나 삶의 가치관이 송두리째 바뀐다. (이혼할거 아니라면) 결혼이란 내 인생의 대부분을 같이 살아갈 인생 동반자를 만나는 아주 큰 사건이기 때문에, 결혼해서 내 가정을 꾸리는 시점부터 내 인생 2막이 시작되는 것과도 같다. 나 역시 결혼 전후로 삶의 자세가 180도 달라졌다.19. 결혼을 때가 되서 조건맞춰서 결혼하다간 인생 전체가 암울해 질지도 모른다그런데, 저런 중요한 '결혼'이라는 사건을 우리는 그냥 때가 되서 조건 맞춰서 양가 인사드리고 해버리는 경우가 많은것 같다. 특히, 대한민국에서 결혼할때 '사랑'이라는 단어를 언급하면 뭔가 어린애 같아 보이는 이상한 문화도 있다. 난 운이 좋게도 정말 사랑하는 인생 반려자를 만나서 결혼했기에 결혼생활 자체가 신혼이니 이런 단계도 없이 마냥 행복하다. 그러하기에 저렇게 '사랑'이라는 개념이 없이 조건맞춰 만난 반려자와 반평생을 살아갈 거를 상상해 보면 참 불쌍해 진다. 그래서 내 주변 미혼자들에게는 항상 이렇게 말한다. '앞으로 인생 80년 꾸준히 사랑할 마음드는 여자가 아니면 절대로 결혼하지 마라'20. 나와 다른것을 이해하는건 생각보다 쉬운일이 아니지만 매우 중요한 일이기도 하다사람 본성인지는 모르겠지만, 내 사고방식과 다른 사람, 내 삶의 방식과 다른 사람을 만나면 대부분은 경계심부터 든다. 어떤 사람들은 본인의 사고방식이 옳음을 남에게 설득하고싶어 한다. 나도 한때 채식주의자가 아닌 시절 내 와이프를 만났을때 (내 와이프는 10살때 부터 동물보호를 위한 채식주의를 하고 있다) 채식주의가 건강에 좋지 않음을 들어서 설득하려고 한 적이 있다. 지금은 나도 채식주의자가 되어 세상을 바라보니 예전에는 보지 못했던 다양한 생명과 환경의 가치가 눈에 보이기 시작한다. 나와 다른 사람을 이해하고, 그 사람이 되어보는것 많큼 큰 배움은 없다.21. 행복감이란 서로 연결되있기 때문에 어느 한 부분에서 행복하지 않다면 전체가 행복하지 않은거와 같다이런 사람들이 있다. '나는 내 일과 회사가 싫지만 가족의 행복을 위해 다니는거야.' 내가 틀릴수도 있지만 나는 행복에 대해 이런 가치관을 가지고 있다 - 내가 행복하지 않으면 우리 가족도 행복하지 않다. 이런 차원에서 내 하루의 반 이상을 보내는 일터가 행복하지 않은데 내가 행복해 질 수 있을까? -가 그냥 곱해져서 +100 x -1 = -100이 되듯이 행복감이라는건 +-개념으로 sum이 되는게 아니라 내가 어느 한 부분에서 불만족 스럽다면 그 삶 전체가 불만족해 질수 있고, 나아가서는 가족 전체가 불만족해 질 수 있는 것이라고 본다. 22. 살아가면서 한번쯤 마이너리티가 되보는게 필요하다우리 대부분이 뭔가 주류에서 벗어나 마이너리티에 속하는 것에 대한 막연한 불안감이 있다. 특히 대한민국 사회에서는 더욱 그러하다. 하지만 아까 20번에서 설명했듯이 마이너리티가 되어 보면 그동안 눈에 보이지 않았던게 보이게 되고, 또 연관된 마이너리티들의 세상이 열리기도 한다. 인생 백세시대에 한평생 주류안에서만 살기 보다는 한번쯤 마이너리티가 의도적으로 되어보는것도 괜찮지 않을까 생각한다.글쓴이는 스팀헌트 (Steemhunt) 라는 스팀 블록체인 기반 제품 큐레이션 플랫폼의 Co-founder 및 디자이너 입니다. 비즈니스를 전공하고 대기업에서 기획자로 일하다가 스타트업을 창업하고 본업을 디자이너로 전향하게 되는 과정에서 경험한 다양한 고군분투기를 연재하고 있습니다.현재 운영중인 스팀헌트 (Steemhunt)는 전 세계 2,500개가 넘는 블록체인 기반 앱들 중에서 Top 10에 들어갈 정도로 전 세계 150개국 이상의 많은 유저들을 보유한 글로벌 디앱 (DApp - Decentralised Application) 입니다 (출처 - https://www.stateofthedapps.com/rankings).스팀헌트 웹사이트 바로가기
조회수 808

혼자 살게 된다면

"제가 독립하고 집을 나온 지 이 제 한 달이 되었는데요. 막상 독립을 하니까 뭐가 필요한지 잘 모르겠어요. 자취 오래 하신 분들 필수품과 조언 좀 해주세요." - JMTGR 님의 사연"안녕하세요. 이제 막 취업에 성공한 신입사원입니다. 졸업 후 오랜 시간을 취준생으로 보내다가 이제야 겨우 직장에 들어가게 되었습니다! 그리고 난생처음으로 경제적으로 부모님께 독립하게 되었는데요. 회사와 집이 거리가 좀 있어서 혼자 집을 구하여 살게 되었습니다. 기대도 되지만 걱정되고.. 부모님 품에 벗어서 혼자 살면서 사회인으로서 잘 해나갈 수 있을지 너무 고민입니다. 조언 또는 팁을 받고 싶습니다!"- 이 XX 님의 사연 언제 우리는 완전히 '독립' 했다고 말할 수 있을까? 부모님과 또는 가족들과 떨어져 혼자 지내는 순간부터 독립이라고 불러야 할까? 아니면 온전한 경제적인 독립이 이루어진 후에야 우리는 완전히 독립한 사회인이라고 불려지는 걸까? 나를 포함한 주변 많은 친구들 그리고 지인들은 대부분 고향을 떠나 학업 또는 취업으로 인해 혼자 독립하여 살고 있다. 그들도 그리고 나도 처음부터 홀로서기가 쉬운 일은 아니었을 거라고 생각한다. 너무 까마득히 오래되어서 기억이 희미해졌지만.. 두 사연을 보고 과연 조금 더 빨리 '독립' 그리고 '사회인'이 된 사람으로서 어떤 조언 또는 경험을 나눠줄 수 있을까 다시 한번 생각해보게 되었다.1. 거주지 선정개인적으로 나는 어느 곳에 살던 늘 회사 또는 학교가 가까운 곳에 살았다. 그 이유는 ‘아침잠‘이 제일 소중했기 때문이다. 아침에 조금 더 잘 수 있다는 그 여유로움. 그 행복은 사실 하루에 큰 영향을 미친다. 그뿐만이 아니다. 퇴근 또는 하교 후에도 집이 가까우면 피곤한 하루가 조금 덜 피로해지는 경험을 하게 된다. 이런 이유로 나는 조금 월세가 더 비싸더라도 걸어 다닐 수 있는 또는 통근시간이 덜 힘든 곳으로 늘 거주지를 선정하곤 했다. 또 하나 좋았던 점은 ‘교통비‘가 들지 않는다는 것이었다. 물론 집세를 그만큼 더 내는 격이긴 했지만 개인적으로 난 학교 또는 직장과 가까운 곳에 거주지를 선정하는 것을 추천하고 싶다.2. 지출비용 최대한 아껴보기 feat. 본가 혼자 살면 생각보다 뭐가 이렇게 살 것도 필요한 것도 그리고 내야 할 공과금도 많은지.. 여러모로 돈이 깨지기 십상이다. 특히 절대 본가에선 돈 내고 사거나 쓰지 않았던 물품들이 가득이다. 예를 들면 ‘화장지’ 아주 대표적인 예다. 늘 집에 있던 그 두루마리 휴지가 글쎄.. 돈 내고 사려 보니 그렇게 아까울 수가 없다. 당연했던 것들이 새로이 보이는 순간이다.치약, 세제, 쿠킹포일 등등 여태 살면서 단 한 번도 내 돈으로 사보지 않았던 물품들이 필수품이 되어버리고 그렇게 자잘하게 쓰는 돈이 꽤나 많이 나간다. 그러면서 다시 한번 느끼게 된다.“아 이 모든 건 돈이었구나..”그리고 우리는 자취생의 필수 매장이라는 다XX에서 여러 가지를 사곤 하는데 사실 난 개인적으로 본가를 이용(?)한다. 아무리 자취를 하고 경제적으로 독립했다고 한들.. 여전히 우리는 마이너스로 살아가게 되니까..여기서 나의 팁은, 본가에 정기적으로 들러 내가 필요한 물품들을 가져온다. 물론, 집에 없을 수도 있지만 웬만한 것들은 신기하게 부모님이 여분을 가지고 계셔서 집을 탈탈 털어오곤 한다. 특히나 ‘화장지‘, ‘치약’ 이런 생필품 뿐만 아니라 ‘김치’ 등 반찬을 받아오면 적어도 1~2주는 생활비를 아낄 수 있다. (부모님 성향에 따라 이 부분은 실행 가능성이 높아질 수도, 낮아질 수도 있다)3. 혼자를 마음껏 즐기기처음 자취를 시작하거나 사회생활을 시작하여 수입이 생기면, 신이 난다. 부모님 품을 떠나, 가족을 떠나 혼자라는 설렘과 두려움 모든 것을 느끼게 된다. 그리고 보통 처음엔 거의 기쁜 마음이 큰 것 같다.“아~내가 이제 드디어 어른되었구나. 혼자 살다니!”이런 마음으로 이제 혼자 어떻게 살면 좋을지에 대한 고민도 해보고 친구들을 집에 초대하고 집에 늦게 귀가해도 괜찮다는 자유를 만끽할 수 있다. 하지만 오랜 자취러, 사회인이 되면 느끼게 되는 순간이 있다. 혼자 먹는 밥이 맛이 없고, 혼자가 싫은 외로운 날과 가족들과 고향이 유난히 그리운 날들이 찾아올 것이다. 생각이 업그레이드되는 날도 온다. 다시 가족과 함께 살고 싶단 생각 또는 다른 누군가와 함께 살고 싶단 생각, 다시 학생이 되어 사회인에서 벗어나고 싶단 생각 등..또한 너무 혼자 오래 살게 되면 혼자가 익숙해 더 이상 누군가와 함께 사는 게 영영 힘들고 불편해지는 일이 될 수도 있다는 점(?)이 단점이 아닐까.어쨌든, 처음 자취를 하고 독립을 하면서 사회가 규정한 ‘어른‘이란 타이틀은 맨 처음 즐길 수 있는, 그때만 느낄 수 있는 하나의 감정이라고 생각하기에 마음껏 즐기라고 말해주고 싶다.4. 결국 우린 '혼자' 개개인의 차가 있겠지만 나는 다른 친구들에 비해 조금 빨리 독립을 하게 되었다. 그래서 그런지 혼자라는 것에 대해 익숙하지만 누군가에게는 가족과 함께 사는 것이 당연한 일이고 항상 함께 해야 할 수도 있다. 하지만 가족이라는 울타리 안에서, 부모님의 보호 안에서도 ‘나’라는 개인이 존재한다. 힘이 들 때 가족 친구들에게 의지할 수 있기에 우리는 힘을 얻고 다시 살아가지만 결국 삶은 ‘혼자‘라는 것을 이해하고 혼자 자취하며 살아가는 지금의 시간이 앞으로의 홀로서기 연습, 앞으로를 살아갈 용기를 터득하는 시간이라고 생각했으면 좋겠다.5. 너무 혼자가 편해지지 않도록 노력하기4번에 분명히 ‘결국 우린 혼자‘라고 해놓았지만, 5번에서 말하고 싶은 요점은 ‘혼자’에 너무 익숙해져버리지 말자는 것이다. 처음과 끝은 혼자일지언정, 우리는 살아가면서 다른 사람들과 함께 살아가게 된다. 아니 그래야만 한다. 혼자 오래 살다 보니 느끼게 된 것은, 혼자가 너무 편해서 가끔 나만 생각하는 이기적인 면모를 발견하게 된다는 것이다. 그러다 보니 나에게 맞춰지지 않는 것은 배척하게 되었고 차라리 혼자가 편하다며 자취방 한 구석에 홀로 있는 나를 종종 발견하곤 했다. 누군가(가족, 친구)에게 의존하는 것도 문제이지만 그렇다고 너무 혼자가 익숙해지지 않도록 노력하는 것도 필요하지 않을까 싶다.안녕하세요. 스푼 라디오입니다.두 분의 사연을 받고, 사실 제가 어떤 말을 해드릴 수 있을까 고민을 많이 했습니다. 조언이라고 하기엔 거창할 것만 같아 저의 경험을 토대로 몇 자 적어보았습니다. 먼저 첫 사회인이 되시고 이제 막 홀로서기를 시작한 두 분께 자취생활에 도움이 될만한 스푼 굿즈 Made in Spoon '숟가락' 그리고 '머그컵'을 보내드리도록 하겠습니다.누구에게나 사연은 있다.당신의 사연, 고민을 함께 나누는 공간 스푼 라디오입니다.사연에 채택되신 스푼 유저 'JMTGR & 이 XX'님께 스푼 라디오 공식 굿즈를 선물로 보내드립니다.여러분의 이야기를 듣고 싶습니다. 스푼 라디오에 사연을 보내주세요.사연에 채택되신 분들께 소정의 선물을 보내드립니다.자세한 사항은 [email protected]으로 문의 바랍니다.
조회수 1269

Event-Driven Programming

Overview마이크로 서비스 사이의 결합도를 낮추고 비동기적인 문제들을 처리할 때는 Event-driven 아키텍쳐가 유용합니다. 이번 글에서는 AWS에서 제공하는 SNS Topic을 이용해 Event-Driven을 알아보겠습니다. Event-Driven Programming프로그램의 제어 흐름이 이벤트의 발생에 의해 결정되는 컴퓨터 프로그래밍 패러다임입니다. publish/subscribe (이하 pub/sub)메시징서버리스 및 MSA에서 안정성 및 확장성을 높이기 위하여 사용되는 비동기 서비스 통신 방법입니다. 게시된 메시지를 다른 시스템에 비동기적으로 전달하고, Topic을 구독하는 모든 구독자는 모든 메시지를 받을 수 있습니다. 특히 게시자는 누가 구독하고 있는지 알지 않아도 되고, 구독자도 메시지의 출처를 알 필요는 없습니다. pub/sub 메시징 기본 / 출처: AWS Compute BlogAmazon SNS Topicpub/sub 방식의 메시징 서비스입니다. AWS의 여러 서비스들이 SNS에 이벤트를 게시할 수 있습니다. SNS Event Publishers / 출처: AWS Compute Blog위의 그림과 같이 구독자는 게시자 서비스에서 트리거된 이벤트에 응답해 필요한 작업을 진행합니다. 예시로 Elastic Transcoder 서비스에서의 Topic을 활용해보겠습니다. 네 가지의 순서를 거칩니다.1. SNS 토픽 생성2. Elastic Transcoder 등록Optional 항목인 Notification 영역에서 상태별 이벤트를 설정할 수 있습니다. On Completion Event에 위에서 생성한 Topic을 선택해 이벤트를 전달받도록 설정합니다. 3. SNS Topic에 구독자로 등록트랜스 코딩이 완료 후 처리할 프로세스를 가진 Lambda 함수 생성하여 위에서 생성한 SNS Topic에 구독자로 등록합니다. 현재 SNS Topic에서 제공하는 프로토콜은 HTTP, HTTPS, Email, Email-JSON, Amazon SQS, Application, AWS Lambda, SMS가 있습니다.4. 서비스 간 이벤트 전달출처: AWS Compute BlogSNS Topic으로 이벤트를 제공하는 AWS 서비스 중 하나를 살펴봤습니다. 이를 이용하면 마이크로 서비스 간에 이벤트를 전달하고 서비스의 분리 및 확장에 유용하게 사용할 수 있습니다.Conclusion오늘은 SNS Topic을 이용한 Event-Driven을 알아봤습니다. 다음 글에서는 마이크로 서비스에서 사용할 수 있는 AWS 서비스들을 다뤄보겠습니다.참고Event-Driven Computing with Amazon SNS and AWS Compute, Storage, Database, and Networking Services글이상근 팀장 | R&D 개발1팀[email protected]브랜디, 오직 예쁜 옷만#브랜디 #개발문화 #개발팀 #업무환경 #인사이트 #경험공유
조회수 1946

ZOYIFUL TALK (3) 강철의 분석술사 아이언이 말하는 데이터 분석의 길

주가 예측 동아리에서 계량팀을 리딩하다 선배 추천으로 ZOYI에 우연히 입사한 게 벌써 이 년 전.어느덧 그는 유수한 리테일 고객들에게 인사이트를 제공하는 애널리스트로 성장했다.고기를 좋아해 동네별 고기 시세는 다 꿰고 있고, 종종 한아름 맛있는 수육을 삶아와 동료들을 즐겁게 하는 고기언아이언(본명 유인제)의 이야기를 들어보았다.ZOYI: 벌써 이 년이 지났습니다. 그동안 어떤 일들을 하셨어요?워크인사이트 분석팀에서 데이터를 가공해 고객들에게 분석 리포트를 제공하고 있습니다.사실 요즘 리테일 업계 경쟁이 치열하거든요, 그러다보니 고객을 잘 유입하는 것 못지않게 고객 경험 관리가 중요해 졌어요.워크인사이트는 스마트폰 무선신호를 기반으로 매장 방문객을 수집, 분석하는 솔루션입니다. 매장의 유동인구부터 방문객, 체류객, 재방문객 등등의 데이터를 가공해 고객들이 실제 액션을 취할 수 있는 가치를 제공하는 일을 하고 있습니다.매장에 설치된 센서를 통해 무선 신호를 수집합니다ZOYI: 어떤 가치를 말하는 건가요?예를 들면, 매장에 들어온 고객들에게 브랜드가 어떤 경험을 전달하고 구매까지 유도 하는지 분석해요.한 매장을 여러 개의 존으로 나누어 각각의 존에 얼마나 방문했고, 얼마나 머물렀는지, 한 존에서 다른 존으로 어떻게 이동했는지 분석하는 거예요. 이를 위해 동선을 세부적으로 보기도 하고, 어떤 공간에 많이 머물렀는지, 실제로 그게 매출로 이어졌는지 등을 관찰해요. 관찰 결과에 기반하여 매대 구성을 변경하기도 하고요. 응대 직원의 배치를 변경하거나 프로모션을 진행하기도 합니다. 그 후 액션 전후를 비교해서 과연 실제로 생각했던 전략들이 알맞게 매출로 이어졌는지를 검증하게 되지요.리모델링 이후 전환율과 체류시간이 모두 향상한 공간분석 사례ZOYI: 워크인사이트 분석만의 특징이 있나요?가장 큰 특징은 저희가 데이터를 직접 가지고 있다는 점이예요. ZOYI에 들어오기 전까지는 데이터를 구하기 어려워 할 수 있는 분석이 제한적이었는데, 덕분에 여기선 원하는 분석을 거의 다 해 볼 수 있어요. 회귀분석이나 연관성 분석같은 기본적인 분석부터, 프로세스 마이닝 및 가설 기반의 공간 분석까지 다양한 경험을 해볼 수 있었어요.신호 데이터를 다룬다는 것도 특징이예요. ZOYI 오기 전에 제가 분석했던 데이터는 대부분 전처리 할 게 없는 깔끔한 데이터였거든요. ZOYI의 경우에는 신호기반의 빅데이터를 다루다 보니, 데이터의 전처리 과정부터 일이 시작됩니다.워크인사이트를 활용해 오프라인 매장의 다양한 분석을 할 수 있습니다ZOYI: 과정을 조금 더 구체적으로 설명주실 수 있으신가요?네, 보통은 다음과 같은 순서로 진행됩니다.우선 고객사의 니즈가 무엇인지 파악한 후, 스토리보드를 만듭니다. 리포트의 전체적인 방향을 설정하는 단계라고 볼 수 있어요.그 다음에 데이터를 들여다 보면서 스토리에 맞는 분석을 진행할 수 있는지 검토하지요. (이 단계에서 데이터 전처리 및 기초적인 통계분석을 진행하고요)데이터 전처리 및 분석 스토리의 방향이 완성이 되고 나면 실제로 분석을 진행하는데요, 과정은 다음과 같습니다. a. 분석 목적/종류에 따라 세부 가설 및 기간, 대조군 설정 b. 데이터를 SQL, 파이썬, R 등으로 각 분석 목적에 따른 데이터셋 추출 c. 데이터 분석 진행 (기초 통계 분석 / regression / 유사도 관점의 clustering 등…)분석 결과는 태블로(Tableau)라는 프로그램을 이용해서 쉽게 이해할 수 있도록 시각화하고 있어요.ZOYI: 기억에 남는 분석 사례가 있나요?1년 차 때 진행했던 패션 브랜드 A의 CRM 리포트가 기억에 남습니다. 브랜드 A는 제가 입사 때부터 맡아온 브랜드라 더 애착이 가요.처음에는 워크인사이트 데이터만을 기본으로 작성했지만, 이 때에는 실제 고객들이 어떻게 반응할지까지 함께 보면 좋겠다는 생각에 CRM 데이터까지 관점을 확대해서 준비했었습니다. 새로운 관점이다 보니, 약 3주 정도 기간을 가지고 진행했었는데 2주차까지는 스토리보드 하나를 잡는데도 시간을 많이 썼어요.사실 리포트를 제공하기 전까지는 고객사 온도가 떨어진다는 느낌을 받았거든요. 피드백이 잘 오지 않고, 실제 업무에 제안내용이 잘 반영되었는지 몰라서 신경이 쓰였었어요.그런 압박감 속에서 리포트를 완성하고, 발표했는데, 고객사가 이건 우리가 지금까지 보지 못한 시각이다, 앞으로 어떻게 해야할지 계획을 짜서 해보겠다고 말씀주셨을 때 정말 보람있었어요. 실제로 브랜드 A는 그 후로 VIP 룰도 정리해서 실제 마케팅에 활용하고 있어요.ZOYI: 힘들면서도 뿌듯했을 것 같아요1년차 때는 사실 분석 하기 바빴어요. 어떤 과제가 주어지면 이걸 어떻게 분석할지, 예전에 썼던 방법론들은 뭐가 있었지 등등을 복기하는 데 시간을 많이 썼던 것 같아요.2년차 되고 나서부터는 분석 내용보다는 저희 고객사 관점에서 더 고민해 볼 수 있게 된 것 같아요. 과거에는 어떤 이야기를 전달할지에만 집중을 해왔다면, 지금은 제 리포트를 보는 사람들이 최근에 가장 필요로 하는 주제가 무엇인지, 우리의 데이터로 고객들의 니즈를 어떻게 채워줄 수 있을지에 집중합니다.ZOYI: 심오해 지셨군요 ㅎㅎ그런가요 ㅎㅎ 결국 고객들이 워크인사이트 데이터를 어떻게 활용해 가치를 만들 수 있는지 도와주는 일이 가장 중요하고, 이를 위해서는 고객과 시장을 더 잘 이해하는 것이 중요한 것 같아요. 그런 의미에서 분석도 좀 더 깊고 넓게 보려고 노력하고 있습니다.ZOYI: 팀원들과도 이런 고민들을 나누시는 편인가요?현재 분석팀에는 모두 7명의 팀원이 있는데요, 어느 정도 역량이 되면 한 명이 하나의 프로젝트를 책임지는 방식으로 업무가 이뤄지고 있어 협업은 많지 않은 편입니다.대신 최근들어 2~3명씩 파트를 나누어 일하고 있는데 상당히 도움이 되는 것 같아요. 같은 파트인 캐서린으로부터 좋은 에너지를 많이 얻고 있습니다. 동시에 같은 프로젝트를 진행하는 일은 많지 않지만, 헷갈릴 수 있는 부분을 같이 물어보고, 캐주얼하게 의견 나누며 브레인스토밍을 할 수 있어요.최근에는 제가 화장품 브랜드의 리포트를 담당할 일이 있었는데, 캐서린이 뷰티 덕후라서 매장의 각 공간에서 사람들이 어떤 감정을 느낄지에 대한 가설들을 풍부하게 던져줬어요. 덕분에 분석 설계를 견고하게 짤 수 있었고 고객들이 굉장히 만족하는 결과를 낼 수 있었습니다.동료들로부터 좋은 에너지를 얻고 있습니다~ZOYI: 그러고 보니 매 주 목요일 아침마다 분석팀 스터디 진행한 지도 벌써 2년이 다 되어가지요?한동안 바빠서 쉬었다가 재개한지 두 달이 조금 지났습니다. 리또스가 진행했던 텍스트마이닝 프로젝트를 복기하는 것부터 진행했어요. 최근에는 데니스가 비즈니스 가설을 세울 때 어떻게 프레임을 접근하는지에 대한 원론적인 이야기들을 사례와 함께 공유해 주기도 했고요.R Shiny를 이용한 대시보드ZOYI: 최근에는 개발 언어인 스칼라도 배웠다고 들었어요.네, 워크인사이트 엔지니어인 휴이한테 함수형 언어를 배우고 있어요. 그동안 SQL 방식으로 분석했던 워크인사이트 데이터를 어떻게 스칼라로 분석할 수 있는지에 대해 배우는 건데요, 휴이가 내주는 문제들이 재미있어요.ZOYI: 스칼라를 이용하면 어떤 것들을 더 해볼 수 있게 되나요?일단 분석 속도가 더 빨라질 거예요. 기존 방식으로는 데이터가 너무 많아서 데이터 추출하는 데에만 하루이틀 걸렸던 작업 시간을 훨씬 단축시킬 수 있어요.장기적으로는 매장의 특성을 이해하는 단계에서 더 나아가 고객을 이해하는 데 인사이트를 얻을 수 있을 것으로 기대합니다. 예를 들어 현재는 ‘‘A와 B 매장을 동시에 방문한 고객은 얼마나 되나?’라는 질문에 대답을 한다면, 앞으로는 ‘C라는 사람은 어느어느 매장을 언제 언제 방문했었나?’라는 질문에 대답할 수 있겠지요.ZOYI: 현재 분석팀 멤버를 충원 중이잖아요, 실제로 2년간 일 해보신 아이언 이야기를 좀 더 들려드리고 싶어요. 아이언은 ZOYI가 첫 직장이었는데, ZOYI에 오기 전 어떤 공부나 활동을 하셨었나요?저는 수학을 전공했어요. 문제를 푸는 게 좋았거든요, 수학적인 문제를 컴퓨터를 이용해서 푸는 과목이 재미있어요. 게임도 블랙잭을 좋아하고 21 도박 영화(?)를 좋아해요.분석은 군대 다녀 와서 대학교 3학년 때 처음 접했어요. 주가 예측 동아리 포스터가 인상이 깊었는데, 그 “I want you for…” 있잖아요, 그 손가락이 저를 가리키는 것 같아서 지원을 했고, 그 동아리에서 좋은 사람들을 많이 만났어요. 원래 수학과이다 보니까 경제를 숫자로 풀어내는 데에 흥미가 있었고요. 그 안에서 회귀분석, 시계열 분석 등을 시작하면서 처음 발을 딛게 되었습니다. 제 인생에서 가장 공부를 열심히 했던 시기였던 것 같아요. 컴퓨터를 이용한 코딩이나 SaaS 툴을 다뤄보기도 했고요.그 이후에도 대부분의 분석은 금융이었어요. 열심히 하고 있다보니 좋아하고, 흥미가 붙어서 계량팀장을 맡아 팀을 리드하기도 했었고. 이후에는 동아리를 잠시 쉬면서 수학과로 돌아갔어요.금융 쪽을 공부하다 보니, 경제에서 중요한 것은 리스크를 관리하던 것이더라고요. 그래서 보험 공부를 하게 됐고요, 하다보니 통계에도 더 관심이 생겼었지요. 그러던 중 대학교 선배 추천으로 우연히 인턴을 시작했던 게… 어느덧 2년 차가 되었네요 허허.ZOYI: 일 해보니 어떤 능력이 가장 필요한 것 같아요?워크인사이트 분석의 경우 리테일 고객들을 대하는 일이라 실제 분석을 진행할 수 있는 분석 스킬 못지않게 리테일 비즈니스를 잘 이해하고 고객들로부터 인사이트를 도출하는 센스가 중요한 것 같아요.명의라면, 단순히 환자를 살펴보는 데에서 그치지 않고 상대방과의 소통을 통해 맥을 잘 짚어내서 무엇을 봐야 하고 치료해야 하는지 잘 알 수 있지 않을까요? 실력 있는 분석가도 마찬가지로 질문을 잘 던지고, 고객의 답변으로부터 문제를 해결할 수 있는 소스를 잘 도출하는 분석가라고 생각합니다.스킬 외적으로는 감정 기복이 심하지 않고 꾸준히 앞으로 나아갈 수 있는 능력이 중요한 것 같아요. 때로는 보고서 일정이 우리 마음대로 조율되지 않을 수도 있고, 정해졌던 기간 내에 퀄리티가 나오지 않을 수도 있거든요. 그런 때에도 잘 해보겠다는 마음가짐이 필요합니다ZOYI: 말만큼 쉬운 일이 아닐 텐데요,맞아요, 어려운 일이예요. 하지만 어려움에도 불구하고 만족감이 높은 이유는, 그런 순간들을 극복한 뒤에 좋은 결과가 나오는 걸 경험했기 때문인 것 같아요. 이런 과정들을 하나씩 지나갔을 때 나에게 더 좋은 밑거름이 되겠구나 하는 생각이 들거든요. 그런 분들께는 ZOYI 분석팀의 환경이 잘 맞을 거예요.ZOYI: 갖춰야 하는 분석 스킬은 무엇이 있을지 궁금합니다.R, Python을 이용한 기본적인 통계분석 경험이 있으면 좋습니다. 하지만 특정 분석 스킬 자체 보다는 공부에 대한 의지가 있는 것이 더 중요해요. 팀에서 요구하는 자질이 다양하기도 하고, 학교나 특정 직장에서 경력을 쌓는다고 배우기 어려운 부분도 많거든요. 공부에 대한 의지만 있으면, 팀에서 같이 하면서 부족한 부분을 채울 수 있어요.ZOYI: 앞으로 어떤 동료들이 더 들어왔으면 좋겠어요?다양한 경험을 하고 온 사람들이 늘어났으면 좋겠어요. 지금도 팀원들 마다 장점이 다 달라서, 여전히 많이 배우고 있거든요. 공간데이터를 잘 다루는 분도 있고, 시각화를 잘 하는 분도 있어요. 분석이론을 다양하게 공부하신 분들께는 분석 방법들을 배울 수 있고요, 업계 경험이 있으신 분께는 분석에 필요한 인사이트들을 얻을 수 있습니다. 제 경우 저는 수학과를 나왔기 때문에, 새로운 분석기법을 빨리 흡수해서 소개할 수 있고요.ZOYI: ZOYI에서 어떻게 성장하고 싶으신가요?앞서 말했듯, 앞으로 고객을 더 잘 이해하고 고객에게 필요한 가치를 전달할 수 있는 분석가로 성장하고 싶어요.궁극적으로는 아이언이라는 분석가로서의 브랜드를 가지고 싶어요, 제가 쓴 보고서라면 사람들이 기대할 수 있는 분석가요. 그러려면 결국 퀄리티와 디테일이 중요할 것 같아요.ZOYI: 이미 ‘아이언 맨’으로서 브랜드를 잘 구축해 나가고 계시다고 생각되는데요 ㅎㅎ 마지막으로 한 마디 부탁드리며, 인터뷰를 마치겠습니다.사실 이런 인터뷰에 답변하는게 좀 오글거리긴 했는데요, 제 생각을 입밖으로 내뱉으면서 지금까지를 돌아볼 수 있어 제게도 즐거운 시간이었습니다. 앞으로도 ZOYIful Talk를 많이 했으면 좋겠습니다!! :-D#조이코퍼레이션 #팀원소개 #팀원인터뷰 #팀원자랑 #기업문화 #조직문화 #데이터분석
조회수 911

[퍼포몸쓰 일상] #0 어쩌다 슬라운드

다니던 회사를 그만두고 한 달 정도 방황했다. 친구들의 동업 제안, 머릿속을 맴도는 사업 아이디어, 이런저런 스카우트 제의. 무엇하나 쉬운 게 없다고 생각했다. 핑계처럼 로켓펀치를 켜고 뻑뻑한 눈알 위를 겉도는 채용공고를 훑었다.딱 하나, 홈에 덜컥 걸리는 느낌이 들었다. 저녁 8시 40분. 입사 지원하고 두 시간이 채 지나지 않아 전화가 걸려왔다. 당황과 반가움 중간 어딘가의 감정을 안고 통화했던 기억이 난다. 그들이 찾던 포지션이 신기할 정도로 나와 맞아떨어진다는 데서 오는 반가움. 굉장히 빠른 액션에서 오는 당황. 전화받고 이틀 후 오전 11시로 인터뷰 약속이 잡혔는데 재밌는 건 그 날이 일요일이었다는 거다. 많은 인터뷰를 봤지만(인터뷰어로서, 인터뷰이로서) 주말 오전 인터뷰는 처음이었다. 좋고 나쁨을 떠나서 나에겐 이례적인 일이라 가벼운 마음으로 갈지, 진중한 마음으로 갈지 갈팡질팡했다.일요일 오전 11시.매트리스 업계의 적폐를 바꾸고 싶다던 두 남자와 만나 가장 먼저 한 이야기는 폴리에스테르 빨대에 관해서였다. 거북이의 콧구멍에서 빨대를 뽑아내는 영상 속 거북이가 얼마나 쾌감에 젖은 표정을 지었는지가 우리의 첫 이야기 소재였다. 아무도 어색해하지 않고 첫 만남에서 그런 이야기부터 시작했다는 게 지금도 조금 어처구니가 없지만 우리는 꽤 진지하게 이야기를 이어나갔다.다른 건 모르겠고, 제품 하나는 잘 만들고 싶었다던 그들은 고맙게도 내가 개인적으로 끄적이던 콘텐츠들을 너무나 마음에 들어했다. 반대로 난 짧은 대화에서도 묻어 나오는 그들의 제품에 대한 자부심과 전문성, 열의가 좋았다. 난 내 길지 않은 커리어의 대부분인 4년 반 정도를 스타트업에서 보냈다. 그래서 초기 스타트업이 멤버의 유능함과는 별개로 얼마나 고단한 길을 걷는지 잘 알고 있다.'그동안 쉼 없이 고생했으니 이번엔 좀 편하게 일하자''일단 돈 많이 주는 곳으로 가자''이름이 알려진 곳으로 가자'이직 고민을 하면서 머릿속을 가득 메웠던 생각들은 결국 사람 앞에 스러졌다. 초기 스타트업에서 굴러다녔던 경험만큼, 능력 있고 좋은 사람들과 같이 일하는 즐거움을 알기에 두 명의 founder와 이야기하면서 다시 한번 가족을 생각하지 않는 이기적인 결정을 내렸다(부모님, 장모님, 마누라 죄송합니다).一切有爲法 如夢幻泡影 如露亦如電 應作如是觀스타트업을 하면서 가장 많이 떠올리는 문구다(참고로 교회 다닌다). 현실의 꿈이 비록 손에 잡히지 않더라도 꿈을 빚기 위해 그렇게 난 슬라운드에 콘텐츠 마케터로 합류했다.  
조회수 1883

Tips for building fast portrait segmentation network with TensorFlow Lite

PrefaceDeep learning has led to a series of breakthroughs in many areas. However, successful deep learning models often require significant amounts of computational resources, memory and power. Deploying efficient deep learning models on mobile devices became the main technological challenge for many mobile tech companies.Hyperconnect developed a mobile app named Azar which has a large fan base all over the world. Recently, Machine Learning Team has been focusing on developing mobile deep learning technologies which can boost user experience in Azar app. Below, you can see a demo video of our image segmentation technology (HyperCut) running on Samsung Galaxy J7. Our benchmark target is a real-time (>= 30 fps) inference on Galaxy J7 (Exynos 7580 CPU, 1.5 GHz) using only a single core.Figure 1. Our network runs fast on mobile devices, achieving 6 ms of single inference on Pixel 1 and 28 ms on Samsung Galaxy J7. Full length video. There are several approaches to achieve fast inference speed on mobile device. 8-bit quantization is one of the popular approaches that meet our speed-accuracy requirement. We use TensorFlow Lite as our main framework for mobile inference. TensorFlow Lite supports SIMD optimized operations for 8-bit quantized weights and activations. However, TensorFlow Lite is still in pre-alpha (developer preview) stage and lacks many features. In order to achive our goal, we had to do the following:Understand details of TensorFlow and Tensorflow Lite implementation.Design our own neural network that can fully utilize optimized kernels of TensorFlow Lite. (Refer to 1, 2 and 3)Modify TOCO: TensorFlow Lite Optimizing Converter to correctly convert unsupported layers. (Refer to 4)Accelerate several quantized-layers with SIMD optimized code. (Refer to 5 and 6)We are willing to share our trials and errors in this post and we hope that readers will enjoy mobile deep learning world :)1) Why is depthwise separable layer fast in Tensorflow Lite ?Implementing low-level programs requires a bit different ideas and approaches than usual. We should be aware that especially on mobile devices using cache memory is important for fast inference.Figure 2. Memory access requires much more energy (640 pJ) than addition or multiplication.Accessing cache memory (8 pJ) is much cheaper than using the main memory (table courtesy of Ardavan Pedram) In order to get insight into how intrinsics instructions are implemented in Tensorflow Lite, we had to analyze some implementations including depthwise separable convolution with 3x3 kernelsBelow we describe some of the main optimization techniques that are used for building lightweight and faster programs.Loop UnrollingCan you spot the difference between the following two code fragments?for (int i = 0; i < 32; i++) { x[i] = 1; if (i%4 == 3) x[i] = 3; } for (int i = 0; i < 8; i++) { x[4*i ] = 1; x[4*i+1] = 1; x[4*i+2] = 1; x[4*i+3] = 3; } The former way is what we usually write, and the latter is loop-unrolled version of former one. Even though unrolling loops are discouraged from the perspective of software design and development due to severe redundancy, with low-level architecture this kind of unrolling has non-negligible benefits. In the example described above, the unrolled version avoids examining 24 conditional statements in for loop, along with neglecting 32 conditional statements of if.Furthermore, with careful implementation, these advantages can be magnified with the aid of SIMD architecture. Nowadays some compilers have options which automatically unroll some repetitive statements, yet they are unable to deal with complex loops.Separate implementation for each caseConvolution layer can take several parameters. For example, in depthwise separable layer, we can have many combinations with different parameters (depth_multiplier x stride x rate x kernel_size). Rather than writing single program available to deal with every case, in low-level architectures, writing number of case-specific implementations is preferred. The main rationale is that we need to fully utilize the special properties for each case. For convolution operation, naive implementation with several for loops can deal with arbitrary kernel size and strides, however this kind of implementation might be slow. Instead, one can concentrate on small set of actually used cases (e.g. 1x1 convolution with stride 1, 3x3 convolution with stride 2 and others) and fully consider the structure of every subproblem.For example, in TensorFlow Lite there is a kernel-optimized implementation of depthwise convolution, targeted at 3x3 kernel size:template <int kFixedOutputY, int kFixedOutputX, int kFixedStrideWidth, int kFixedStrideHeight> struct ConvKernel3x3FilterDepth8 {}; Tensorflow Lite further specifies following 16 cases with different strides, width and height of outputs for its internal implementation:template <> struct ConvKernel3x3FilterDepth8<8, 8, 1, 1> { ... } template <> struct ConvKernel3x3FilterDepth8<4, 4, 1, 1> { ... } template <> struct ConvKernel3x3FilterDepth8<4, 2, 1, 1> { ... } template <> struct ConvKernel3x3FilterDepth8<4, 1, 1, 1> { ... } template <> struct ConvKernel3x3FilterDepth8<2, 2, 1, 1> { ... } template <> struct ConvKernel3x3FilterDepth8<2, 4, 1, 1> { ... } template <> struct ConvKernel3x3FilterDepth8<1, 4, 1, 1> { ... } template <> struct ConvKernel3x3FilterDepth8<2, 1, 1, 1> { ... } template <> struct ConvKernel3x3FilterDepth8<4, 2, 2, 2> { ... } template <> struct ConvKernel3x3FilterDepth8<4, 4, 2, 2> { ... } template <> struct ConvKernel3x3FilterDepth8<4, 1, 2, 2> { ... } template <> struct ConvKernel3x3FilterDepth8<2, 2, 2, 2> { ... } template <> struct ConvKernel3x3FilterDepth8<2, 4, 2, 2> { ... } template <> struct ConvKernel3x3FilterDepth8<2, 1, 2, 2> { ... } template <> struct ConvKernel3x3FilterDepth8<1, 2, 2, 2> { ... } template <> struct ConvKernel3x3FilterDepth8<1, 4, 2, 2> { ... } Smart Memory Access PatternSince low-level programs are executed many times in repetitive fashion, minimizing duplicated memory access for both input and output is necessary. If we use SIMD architecture, we can load nearby elements together at once (Data Parallelism) and in order to reduce duplicated read memory access, we can traverse the input array by means of a snake-path.Figure 3. Memory access pattern for 8x8 output and unit stride, implemented in Tensorflow Lite's depthwise 3x3 convolution. The next example which is targeted to be used in much smaller 4x1 output block also demonstrates how to reuse preloaded variables efficiently. Note that the stored location does not change for variables which are loaded in previous stage (in the following figure, bold variables are reused):Figure 4. Memory access pattern for 4x1 output and stride 2, implemented in Tensorflow Lite's depthwise 3x3 convolution. 2) Be aware of using atrous depthwise convolutionAtrous (dilated) convolution is known to be useful to achieve better result for image segmentation[1]. We also decided to use atrous depthwise convolution in our network. One day, we tried to set stride for atrous depthwise convolution to make it accelerate computation, however we failed, because the layer usage in TensorFlow (≤ 1.8) is constrained.In Tensorflow documentation of tf.nn.depthwise_conv2d (slim.depthwise_conv2d also wraps this function), you can find this explanation of rate parameter.rate: 1-D of size 2. The dilation rate in which we sample input values across the height and width dimensions in atrous convolution. If it is greater than 1, then all values of strides must be 1.Even though TensorFlow doesn’t support strided atrous function, it doesn’t raise any error if you set rate > 1 and stride > 1. <!-- The output of layer doesn't seem to be wrong. -->>>> import tensorflow as tf >>> tf.enable_eager_execution() >>> input_tensor = tf.constant(list(range(64)), shape=[1, 8, 8, 1], dtype=tf.float32) >>> filter_tensor = tf.constant(list(range(1, 10)), shape=[3, 3, 1, 1], dtype=tf.float32) >>> print(tf.nn.depthwise_conv2d(input_tensor, filter_tensor, strides=[1, 2, 2, 1], padding="VALID", rate=[2, 2])) tf.Tensor( [[[[ 302.] [ 330.] [ 548.] [ 587.]] [[ 526.] [ 554.] [ 860.] [ 899.]] [[1284.] [1317.] [1920.] [1965.]] [[1548.] [1581.] [2280.] [2325.]]]], shape=(1, 4, 4, 1), dtype=float32) >>> 0 * 5 + 2 * 6 + 16 * 8 + 9 * 18 # The value in (0, 0) is correct 302 >>> 0 * 4 + 2 * 5 + 4 * 6 + 16 * 7 + 18 * 8 + 20 * 9 # But, the value in (0, 1) is wrong! 470 Let’s find the reason why this difference happened. If we just put tf.space_to_batch and tf.batch_to_space before and after convolution layer, then we can use convolution operation for atrous convolution (profit!). On the other hand, it isn’t straightforward how to handle stride and dilation together. In TensorFlow, we need to be aware of this problem in depthwise convolution.3) Architecture design principles for efficient segmentation networkUsually segmentation takes more time than classification since it has to upsample high spatial resolution map. Therefore, it is important to reduce inference time as much as possible to make the application run in real-time.It is important to focus on spatial resolution when designing real-time application. One of the easiest ways is to reduce the size of input images without losing accuracy. Assuming that the network is fully convolutional, you can accelerate the model about four times faster if the size of input is halved. In literature[2], it is known that small size of input images doesn’t hurt accuracy a lot.Another simple strategy to adopt is early downsampling when stacking convolution layers. Even with the same number of convolution layers, you can reduce the time with strided convolution or pooling within early layers.There is also a tip for selecting the size of input image when you use Tensorflow Lite quantized model. The optimized implementations of convolution run best when the width and height of image is multiple of 8. Tensorflow Lite first loads multiples of 8, then multiples of 4, 2 and 1 respectively. Therefore, it is the best to keep the size of every input of layer as a multiple of 8.Substituting multiple operations into single operation can improve speed a bit. For example, convolution followed by max pooling can be usually replaced by strided convolution. Transpose convolution can also be replaced by resizing followed by convolution. In general, these operations are substitutable because they perform the same role in the network. There are no big empirical differences among these operations. <!-- substitutable -->Tips described above help to accelerate inference speed but they can also hurt accuracy. Therefore, we adopted some state-of-the-art blocks rather than using naive convolution blocks.Figure 5.  Atrous spatial pyramid pooling (figure courtesy of Liang-Chieh Chen) Atrous spatial pyramid pooling[1] is a block which mimics the pyramid pooling operation with atrous convolution. DeepLab uses this block in the last layer.We also substitute most of the convolution layers with efficient depthwise separable convolution layers. They are basic building blocks for MobileNetV1[3] and MobileNetV2[4] which are well optimized in Tensorflow Lite.4) Folding batchnorm into atrous depthwise convolutionWhen quantizing convolution operation followed by batchnorm, batchnorm layer must be folded into the convolution layers to reduce computation cost. After folding, the batchnorm is reduced to folded weights and folded biases and the batchnorm-folded convolution will be computed in one convolution layer in TensorFlow Lite[5]. Batchnorm gets automatically folded using tf.contrib.quantize if the batchnorm layer comes right after the convolution layer. However, folding batchnorm into atrous depthwise convolution is not easy.In TensorFlow’s slim.separable_convolution2d, atrous depthwise convolution is implemented by adding SpaceToBatchND and BatchToSpaceND operations to normal depthwise convolution as mentioned previously. If you add a batchnorm to this operation by including argument normalizer_fn=slim.batch_norm, batchnorm does not get attached directly to the convolution layer. Instead, the graph will look like the diagram below: SpaceToBatchND → DepthwiseConv2dNative → BatchToSpaceND → BatchNorm The first thing we tried was to modify TensorFlow quantization to fold batchnorm bypassing BatchToSpaceND without changing the order of operations. With this approach, the folded bias term remained after BatchToSpaceND, away from the convolution layer. Then, it became separate BroadcastAdd operation in TensorFlow Lite model rather than fused into convolution. Surprisingly, it turned out that BroadcastAdd was much slower than the corresponding convolution operation in our experiment:Timing log from the experiment on Galaxy S8 ... [DepthwiseConv] elapsed time: 34us [BroadcastAdd] elapsed time: 107us ... To remove BroadcastAdd layer, we decided to change the network itself instead of fixing TensorFlow quantization. Within slim.separable_convolution2d layer, we swapped positions of BatchNorm and BatchToSpaceND. SpaceToBatchND → DepthwiseConv2dNative → BatchNorm → BatchToSpaceND Even though batchnorm relocation could lead to different outputs values compared to the original, we did not notice any degradation in segmentation quality.5) SIMD-optimized implementation for quantized resize bilinear layerAt the time of accelerating TensorFlow Lite framework, conv2d_transpose layer was not supported. However, we could use ResizeBilinear layer for upsampling as well. The only problem of this layer is that there is no quantized implementation, therefore we implemented our own SIMD quantized version of 2x2 upsampling ResizeBilinear layer.Figure 6. 2x2 bilinear upsampling without corner alignnment. To upsample image, original image pixels (red circles) are interlayed with new interpolated image pixels (grey circles). In order to simplify implementation we do not compute pixel values for the bottommost and rightmost pixels, denoted as green circles.for (int b = 0; b < batches; b++) { for (int y0 = 0, y = 0; y <= output_height - 2; y += 2, y0++) { for (int x0 = 0, x = 0; x <= output_width - 2; x += 2, x0++) { int32 x1 = std::min(x0 + 1, input_width - 1); int32 y1 = std::min(y0 + 1, input_height - 1); ResizeBilinearKernel2x2(x0, x1, y0, y1, x, y, depth, b, input_data, input_dims, output_data, output_dims); } } } Every new pixel value is computed for each batch separately. Our core function ResizeBilinearKernel2x2 computes 4 pixel values across multiple channels at once.Figure 7. Example of 2x2 bilinear upsampling of top left corner of image. (a) Original pixel values are simply reused and (b) – (d) used to interpolate new pixel values. Red circles represent original pixel values. Blue circles are new interpolated pixel values computed from pixel values denoted as circles with black circumference. NEON (Advanced SIMD) intrinsics enable us to process multiple data at once with a single instruction, in other words processing multiple data at once. Since we deal with uint8 input values we can store our data in one of the following formats uint8x16_t, uint8x8_t and uint8_t, that can hold 16, 8 and 1 uint8 values respectively. This representation allows to interpolate pixel values across multiple channels at once. Network architecture is highly rewarded when channels of feature maps are multiples of 16 or 8:// Handle 16 input channels at once int step = 16; for (int ic16 = ic; ic16 <= depth - step; ic16 += step) { ... ic += step; } // Handle 8 input channels at a once step = 8; for (int ic8 = ic; ic8 <= depth - step; ic8 += step) { ... ic += step; } // Handle one input channel at once for (int ic1 = ic; ic1 < depth; ic1++) { ... } SIMD implementation of quantized bilinear upsampling is straightforward. Top left pixel value is reused (Fig. 7a). Bottom left (Fig. 7b) and top right (Fig. 7c) pixel values are mean of two adjacent original pixel values. Finally, botom right pixel (Fig. 7d) is mean of 4 diagonally adjacent original pixel values.The only issue that we have to take care of is 8-bit integer overflow. Without a solid knowledge of NEON intrinsics we could go down the rabbit hole of taking care of overflowing by ourself. Fortunately, the range of NEON intrinsics is broad and we can utilize those intrinsics that fit our needs. The snippet of code below (using vrhaddq_u8) shows an interpolation (Fig. 7d) of 16 pixel values at once for bottom right pixel value:// Bottom right output_ptr += output_x_offset; uint8x16_t left_interpolation = vrhaddq_u8(x0y0, x0y1); uint8x16_t right_interpolation = vrhaddq_u8(x1y0, x1y1); uint8x16_t bottom_right_interpolation = vrhaddq_u8(left_interpolation, right_interpolation); vst1q_u8(output_ptr, bottom_right_interpolation); 6) Pitfalls in softmax layer and demo codeThe first impression of inference in TensorFlow Lite was very slow. It took 85 ms in Galaxy J7 at that time. We tested the first prototype of TensorFlow Lite demo app by just changing the output size from 1,001 to 51,200 (= 160x160x2)After profiling, we found out that there were two unbelievable bottlenecks in implementation. Out of 85 ms of inference time, tensors[idx].copyTo(outputs.get(idx)); line in Tensor.java took up to 11 ms (13 %) and softmax layer 23 ms (27 %). If we would be able to accelerate those operations, we could reduce almost 40 % of the total inference time!First, we looked at the demo code and identified tensors[idx].copyTo(outputs.get(idx)); as a source of problem. It seemed that the slowdown was caused by copyTo operation, but to our surprise it came from int[] dstShape = NativeInterpreterWrapper.shapeOf(dst); because it checks every element (in our case, 51,200) of array to fill the shape. After fixing the output size, we gained 13 % speedup in inference time.<T> T copyTo(T dst) { ... // This is just example, of course, hardcoding output shape here is a bad practice // In our actual app, we build our own JNI interface with just using c++ code // int[] dstShape = NativeInterpreterWrapper.shapeOf(dst); int[] dstShape = {1, width*height*channel}; ... } The softmax layer was our next problem. TensorFlow Lite’s optimized softmax implementation assumes that depth (= channel) is bigger than outer_size (= height x width). In classification task, the usual output looks like [1, 1(height), 1(width), 1001(depth)], but in our segmentation task, depth is 2 and outer_size is multiple of height and width (outer_size » depth). Implementation of softmax layer in Tensorflow Lite is optimized for classification task and therefore loops over depth instead of outer_size. This leads to unacceptably slow inference time of softmax layer when used in segmentation network.We can solve this problem in many different ways. First, we can just use sigmoid layer instead of softmax in 2-class portrait segmentation. TensorFlow Lite has very well optimized sigmoid layer.Secondly, we could write SIMD optimized code and loop over depth instead of outer_size. You can see similar implementation at Tencent’s ncnn softmax layer, however, this approach has still its shortcomings. Unlike ncnn, TensorFlow Lite uses NHWC as a default tensor format:Figure 8. NHWC vs NCHW In other words, for NHWC, near elements of tensor hold channel-wise information and not spatial-wise. It is not simple to write optimized code for any channel size, unless you include transpose operation before and after softmax layer. In our case, we tried to implement softmax layer assumming 2-channel output.Thirdly, we can implement softmax layer using pre-calculated lookup table. Because we use 8-bit quantization and 2-class output (foreground and background) there are only 65,536 (= 256x256) different combinations of quantized input values that can be stored in lookup table:for (int fg = 0; fg < 256; fg++) { for (int bg = 0; bg < 256; bg++) { // Dequantize float fg_real = input->params.scale * (fg - input->params.zero_point); float bg_real = input->params.scale * (bg - input->params.zero_point); // Pre-calculating Softmax Values ... // Quantize precalculated_softmax[x][y] = static_cast<uint8_t>(clamped); } } ConclusionIn this post, we described the main challenges we had to solve in order to run portrait segmentation network on mobile devices. Our main focus was to keep high segmentation accuracy while being able to support even old devices, such as Samsung Galaxy J7. We wish our tips and tricks can give a better understanding of how to overcome common challenges when designing neural networks and inference engines for mobile devices.At the top of this post you can see portrait segmentation effect that is now available in Azar app. If you have any questions or want to discuss anything related to segmentation task, contact us at [email protected]. Enjoy Azar and mobile deep learning world!References[1] L. Chen, G. Papandreou, F. Schroff, H. Adam. Rethinking Atrous Convolution for Semantic Image Segmentation. June 17, 2017, https://arxiv.org/abs/1706.05587[2] C. Szegedy, V. Vanhoucke, S. Ioffe, J. Shlens, Z. Wojna. Rethinking the Inception Architecture for Computer Vision. December 11, 2015, https://arxiv.org/abs/1512.00567[3] A. Howard, M. Zhu, B. Chen, D. Kalenichenko, W. Wang, T. Weyand, M. Andreetto, H. Adam. MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications, April 17, 2017, https://arxiv.org/abs/1704.04861[4] M. Sandler, A. Howard, M. Zhu, A. Zhmoginov, L. Chen. MobileNetV2: Inverted Residuals and Linear Bottlenecks. January 18, 2018, https://arxiv.org/abs/1801.04381[5] B. Jacob, S. Kligys, B. Chen, M. Zhu, M. Tang, A. Howard, H. Adam, D. Kalenichenko. Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference. December 15, 2017, https://arxiv.org/abs/1712.05877
조회수 1258

EOS Token 생성과 발행, 전송

이번시간에는 배포한 Contract를 통해 Token 발행과 전송을 해보겠습니다. 이를 위한 준비는 아래 2미디엄 글을 참조해주세요EOS Smart Contract 를 위한 준비EOS Smart Contract 배포먼저 저번 시간에 배포한 token 발행 abi 를 확인해 보겠습니다.$ cleos get abi hexlanthenryget abiabi를 확인하다보면 actions 라는 항목에 총 3개의 action이 있음을 확인할 수 있습니다. 이 3개의 name이 실행할 수 있는 action입니다. token발행은 create action을 통해 진행할 수 있습니다.Token 생성$ cleos push action hexlanthenry create '["hexlanthenry", "10000000000.0000 HEX"]' -p hexlanthenrycreate action 실행 결과create action 을 통해 ‘HEX’ 토큰을 100억개 생성했습니다. create 라는 action의 인자는 account_name(hexlanthenry), maximum_supply(10000000000.0000 HEX) 입니다. 즉 첫번째 인자는 토큰의 발행자를 나타내며, 두번째 인자는 토큰의 최대 수량을 나타냅니다.이 인자가 어떻게 들어가는지는 abi 의 struct 를 확인하면 알 수 있습니다.abi의 create structparameter 1 : account_name type— issuerparameter 2 : asset type — maximum_supply+ 저번 강의에서 공지한데로 다음 포스팅에서는 abi가 무엇을 뜻하는지, 이를 통해 어떻게 action을 실행할 수 있는지 알아보도록 하겠습니다.Token 발행생성과 발행 이 2개의 개념이 헷갈릴 수 있습니다. create action을 통한 생성은 최대 발행량을 결정 하는 것이며, issue action 은 토큰을 유통 시키는 것입니다.create : token 생성과 동시에 최대 발행량 결정issue : token 의 유통따라서 issue action을 통해 이전에 생성한 HEX token을 발행해보겠습니다.$ cleos push action hexlanthenry issue '["hexlanthenry", "10000.0000 HEX", "initial issue"]' -p hexlanthenryissue contract 실행 결과issue action 역시 data로 어떤 인자가 들어가는지는 abi를 통해 확인 가능합니다.abi의 issue structparameter 1 : account_name type — toparameter 2 : asset type — quantityparameter 3 : string type — memomemo 는 transfer 가 어떤 목적인지에 대해 설명해주는 인자 입니다. 생략해도 되는 값으로, 원하시면 parameter 개수를 유지하는 선에서 empty string을 넣으시면 됩니다. memo를 어떻게 쓰면 유용한지에 대해서도 다른 포스팅에 담도록 하겠습니다.issue가 잘 실행 되었는지 확인해 보겠습니다.$ cleos get currency balance hexlanthenry hexlanthenry저는 issue 를 4번 수행한 후 balance 를 체크 했기 때문에 총 40000개의 HEX token이 존재하는 것을 확인 할 수 있습니다.hexlanthenry 의 HEX token개수예외사항1create 하지 않은 token을 issue 할 경우해당 symbol 이 존재하지 않음예외사항2생성한 token 수보다 많은 양을 issue 할 경우maximum supply를 초과함Token transfer마지막으로 token을 다른 계정에 전송 해보도록 하겠습니다. 다른계정에 token을 보내야 하기 때문에 계정을 생성하거나 존재하고 있는 계정을 사용하시면 됩니다.아래 명령으로 hexlanthenry 계정이 babylion1234 계정으로 10000개의 HEX 토큰을 보냅니다.$ cleos push action hexlanthenry transfer '["hexlanthenry", "babylion1234", "10000.0000 HEX", "first"]' -p hexlanthenrytransfer 실행결과transfer 시 들어가는 data에 대해서도 abi를 확인해보겠습니다. 다른 action보다 많은 인자를 필요로 합니다. [“hexlanthenry”, “babylion1234”, “10000.0000 HEX”, “first”]abi의 transfer structparameter 1 : account_name type — fromparameter 2 : account_name type — toparameter 3 : asset type — quantityparameter 4 : string type — memo실제로 babylion1234 계정을 확인해 보면, 방금 배포한 HEX token을 보유하고있는 것을 확인할 수 있습니다.babylion1234의 HEX 보유이번 포스팅에서는 token을 생성과 발행 그리고 전송을 다뤄봤습니다. EOS는 Ethereum 과 달리 토큰 발행을 매우 쉽게 진행할 수 있습니다. 이 두 dapp의 차이에 대해서도 포스팅을 하고 싶으나 우선 다음 포스팅에서는 contract 개발의 기초를 다루도록 하겠습니다.감사합니다.#헥슬란트 #HEXLANT #블록체인 #개발자 #개발팀 #기술기업 #기술중심
조회수 1243

vulcan과 buildpack을 이용한 Heroku 바이너리 배포

vulcan과 buildpack을 이용한 Heroku 바이너리 배포안녕하세요. 스포카 개발팀에서 서버 관련 개발 업무를 담당하고 있는 문성원입니다. 오늘은 저희가 사용하는 PasS(Platform as a service)인 Heroku에 직접 바이너리를 빌드하여 올리는 방법을 함께 알아보겠습니다.Why?________________________________________지난주 저희 개발팀은 새로운 상점 사진을 출력하기 위해 한 사진을 비율이 다른 이미지로 바꿔서 저장하는 작업을 해야 했습니다. 다행히 이 문제는 Seam carving, 혹은 Liquid rescaling으로 불리는 방법, 그리고 이를 구현한 ImageMagick과 그 Python 바인딩인 wand로 쉽게 해결할 수 있을 것 같았습니다. (Seam carving과 wand에 대해서는 이 글을 읽어보시는 것을 권합니다.)그런데 막상 서비스에 배포하려니 한가지 문제가 있었습니다. 저희는 최근 서비스를 Heroku에서 운영 중인데, 이 Heroku에 ImageMagick 라이브러리는 깔렸었지만, liblqr이 없어 Liquid rescalig이 불가능한 상태였던 겁니다. 개발자의 로컬에서 테스트할 때야 소스를 받아서 직접 빌드라도하면 되지만 이 고지식한 PasS에서 그건 무리였죠.결국, 저희는 Heroku의 배포 도구인 buildpack과 바이너리를 빌드하기 위한 서버인 Vulcan에 대해서 조사했습니다.Workflow________________________________________Heroku 앱에 사용할 바이너리를 만드는 데는 크게 2가지 과정이 필요합니다. 먼저 빌드 서버인 Vulcan을 통해 필요한 바이너리를 Heroku(정확히는 아마존 EC2)용으로 빌드해야하며, 이를 buildpack을 통해 새로 만들거나 운영 중인 앱에 적용해야 합니다.재미있는 점은 Vulcan 서버 역시 Node.js로 작성된 Heroku 앱이기때문에 buildpack을 적용할 수 있습니다. 즉 위와 같은 상황이라면 먼저 liblqr을 빌드한 뒤 이를 Node.js 용 buildpack에 적용해서 Vulcan에 올린 뒤 ImageMagick을 빌드해야 합니다.I am a Vulcan, bred to peace________________________________________우선 Vulcan부터 깔아보겠습니다. (Ruby와 Heroku 계정이 필요합니다. 경우에 따라선 sudo가 필요할 수 있습니다.)$ gem install vulcan그다음 빌드에 사용할 서버 애플리케이션을 vulcan 커맨드를 통해 만듭니다. (눈치채신 분도 계시겠지만 앱 이름은 적당히 바꿔서 지으셔야 에러가 안 납니다.)$ vulcan create vulcan-dodo-dev혹시 모르니 만들어진 서버의 업데이트를 한번 해줍시다.$ vulcan update --app vulcan-dodo-devIf I could change to liquid…________________________________________이제 본격적으로 빌드를 해봅시다. 먼저 필요한 건 liblqr입니다. 소스를 적당한 디렉터리에 내려받아 풀어둡니다.$ wget http://liblqr.wikidot.com/local--files/en:download-page/liblqr-1-0.4.1.tar.bz2$ tar xzf liblqr-1-0.4.1.tar.bz2최신 소스를 원하신다면 git 저장소를 복제하셔도 됩니다.$ git clone git://repo.or.cz/liblqr.git편하신 대로 소스를 다 내려받으셨다면 이제 앞서 생성한 Vulcan을 통해 이를 빌드해봅시다.$ cd liblqr$ vulcan buildVulcan은 현재 디렉토리의 소스를 모두 묶어서 EC2상의 서버로 올린 뒤 그 서버에서 빌드한 바이너리를 다시 사용자의 컴퓨터로 내려줍니다. 이제 이를 buildpack을 통해 Vulcan 서버(vulcan-dodo-dev)에 적용해야 합니다.Buildpack is ready________________________________________buildpack을 직접 만들어 적용하는 건 아주 쉽습니다. 우선 다음 명령어로 Node.js용 buildpack을 복제합니다.$ git clone git://github.com/heroku/heroku-buildpack-nodejs.git그다음에는 Heroku용으로 빌드된 liblqr을 Heroku 앱 빌드시 포함시키기 위해 bin/compile파일의 마지막에 다음 코드를 추가합니다. (앞서 빌드한 liblqr을 외부에서 접근할 수 있게끔 적당한 장소(ex. Amazon S3, 혹은 Dropbox의 Public 디렉터리등)에 올려둬야 합니다.)# liblqr                                                                                  LIBLQR_BINARY="https://dl.dropbox.com/u/55786385/liblqr-1-0.4.tgz"                        SPOQA_VM_VENDOR="vendor/spoqa/liblqr"                                                    mkdir -p $1/SPOQA_VM_VENDOR                                                            curl $LIBLQR_BINARY -o - | tar -xz -C $1/$SPOQA_VM_VENDOR -f -이제 buildpack을 커밋(commit)한뒤 적당한 공개 저장소(ex. github) 등에 올려(push)둡니다. 그리고 나선 아까 만든 Vulcan 앱(vulcan-dodo-dev)의 buildpack을 다음 명령어로 지정합니다.$ heroku config:set BUILDPACK_URL=https://github.com/spoqa/heroku-buildpack-nodejs.git --app vulcan-dodo-dev마지막으로 Vulcan 앱을 업데이트하여 새 buildpack을 반영시킵니다.$ vulcan update --app vulcan-dodo-dev확인을 위해서 Vulcan 앱에 들어가 보는 것도 좋습니다.$ heroku run bash --app vulcan-dodo-devheroku run bash --app vulcan-dodo-devRunning `bash` attached to terminal...~ $ ls vendor/ls vendor/spoqa  gemsIt’s a kind of magic________________________________________이제 liblqr을 이용해서 ImageMagick을 빌드해보죠. 기본적으로는 liblqr을 빌드할때와 다르지 않지만 ./configure를 통해 옵션을 줘야 하기에 build 커맨드가 좀 복잡해집니다.vulcan build -p /tmp/ImageMagick -c "export PKG_CONFIG_PATH=/app/vendor/spoqa/liblqr/lib/pkgconfig && export CFLAGS=-I/app/vendor/spoqa/liblqr/include/lqr-1 && LD_LIBRARY_PATH=/app/vendor/spoqa/liblqr/lib && ./configure --prefix=/tmp/ImageMagick --with-lqr && make install" -v조금만 자세히 살펴보면, -p 옵션으로 내려받을 경로를 지정하고 -c 옵션으로 실제 빌드에 사용할 커맨드를 지정합니다.(-v는 짐작하시다시피 확인을 위한 verbose 옵션입니다.) 앞서 수정한 buildpack에서 liblqr은 /app/vendor/spoqa/liblqr 밑에 설치되게끔 되어있기에 PKG_CONFIG와 CFLAGS 설정을 추가해주고 --with-lqr을 줘서 LQR 딜리게이트(Delegate)를 활성화 시킵니다.On your mark________________________________________이렇게 만들어진 ImageMagick 바이너리와 liblqr 바이너리를 실 서버에 적용할 buildpack에 추가해주면 이 험난한 여정도 끝입니다. 앞서 했던것처럼 대상 서버에 맞는 buildpack을 똑같이 복제합니다. (여기서는 Python을 사용합니다.)$ git clone git://github.com/heroku/heroku-buildpack-python.gitbin/compile을 고치는 것도 추가해야 할 라이브러리가 2개라는 점만 빼면 거의 같습니다.# ImageMagick with lqr                                                                                                                  LQR_BINARY="https://dl.dropbox.com/u/55786385/liblqr-1-0.4.tgz"IMAGE_MAGICK_BINARY="https://dl.dropbox.com/u/55786385/ImageMagick-6.8.tgz"IMAGE_MAGICK_WITH_LQR_DIR="vendor/ImageMagick+lqr"mkdir -p $1/$IMAGE_MAGICK_WITH_LQR_DIRcurl $IMAGE_MAGICK_BINARY -o - | tar -xz -C $1/$IMAGE_MAGICK_WITH_LQR_DIR -f -curl $LQR_BINARY -o - | tar -xz -C $1/$IMAGE_MAGICK_WITH_LQR_DIR -f -똑같이 고친 buildpack을 커밋, (적당한 저장소에) 푸시하고 대상 서버의 BUILDPACK_URL을 바꿔줍니다.$ heroku config:set BUILDPACK_URL=https://github.com/spoqa/heroku-buildpack-python.git --app dodo-dev바뀐 buildpack을 적용하기 위해서 빈 커밋을 만들어 새로 배포해보겠습니다.$ git commit --allow-empty -m "empty commit"$ git push heroku master마지막으로 대상 서버의 설정을 바꿔줍니다.$ heroku config:set MAGICK_HOME=/app/vendor/ImageMagick+lqr LD_PRELOAD=/app/vendor/ImageMagick+lqr/lib/libMagickCore.so --app dodo-dev#스포카 #개발 #개발자 #개발팀 #개발팁 #꿀팁 #인사이트

기업문화 엿볼 때, 더팀스

로그인

/