스토리 홈

인터뷰

피드

뉴스

조회수 1699

스팀헌트 피칭

스팀헌트 프로젝트를 시작한지 1년 반, 남들은 제품 만들기도 전에 백서 하나로 ICO부터 해서 돈 부터 끌어모아서 사업하는 이바닥에서 우리는 거꾸로 제품부터 만들어 1년 넘게 운영하다가 이제 IEO (Initial Exchange Offering)를 통해 펀드를 모집하고 있다. 우리가 이렇게 정 반대의 트리를 타게 된 1년 반의 여정을 아주 솔직하게 풀어보려고 한다.1. 심플한 시작2017년 여름. 비트코인이 2천불을 넘어 고공행진을 하려 용트림을 하던 그 시기. 이 글을 읽는 대부분의 사람들처럼 우리 팀 역시 이 "대세"에 합류하고자 블록체인 사업에 뛰어들었다.솔직히 세상을 바꾸겠다는 포부나 사토시 나카모토의 이상을 실현한다는 둥의 그런 거창한 목표따윈 있지도 않았다. 제품 개발을 즐기는 우리들에게 (그래서 해카톤 나가서 상 타오는게 취미인 우리들에게) 블록체인이란 그저 신기하고 재미난 장난감, 그리고 잘만 하면 뭔가 용돈벌이좀 되겠다는 생각이 전부였다.우리 팀은 원채 소셜쪽에 관심이 많았기에 (이 전에 했던 제품 역시 바크 (Bark)라는 개가되어 짖어보자는 요상한 컨셉의 소셜 앱이였다), 자연스럽게 스팀 (Steem)이라는 블록체인에 관심을 갖게 되었다. 솔직히 스팀잇 (스팀 블록체인에서 돌아가는 최초의 DApp) 보다는 컨텐츠와 보팅이라는 단 두개의 아주 심플한 단위를 가지고 복잡한 토큰 경제가 결합된 댑을 만들 수 있다는 점에 매료되어 미친듯이 스팀 위에서 할만한 아이템을 찾게 되었고, 마침 우리가 활발하게 활동하고 있던 "프로덕헌트 (https://www.producthunt.com/)"에 스팀 토큰 경제를 붙이면 뭔가 그림이 나올것 같다는 생각이 들어 바로 5개월동안 하던거 다 제껴두고 제품 만들기에 들어갔다.2017년 10월 31일 우리 이런거 개발중이라고 스팀 커뮤니티에 처음 공개한 글 - Introducing SteemHunt: Steem Fueled ProductHunt - Make money by discovering cool products every day(남들 팀 짜고 백서 부터 만들어서 신나게 ICO로 돈 긁어모으고 있을때 우리는 이러고 있었다...)2. 단 100명이지만 뜨거웠던 초기 유저드디어 2018년 3월 5일, 스팀 커뮤니티에 두둥~! 하고 스팀헌트라는 제품을 선보였다. 스팀헌트는 테크 얼리어답터들이 인터넷에서 발견한 테크 관련 신박한 제품들을 "나 오늘 이런거 발견했는데 어떰? ㅇㅈ?" 이런 느낌으로 간단하게 공유하고, 서로 니꺼가 쿨하네, 내꺼가 더 ㅇㅈ네 하면서 랭킹 경쟁을 벌이는 커뮤니티 사이트 이다. 이걸 스팀 위에서 돌림으로써, 저런 서로의 덕후심을 뽐내는 이들이 스팀 토큰 보상을 받을 수 있어 더욱 덕후활동을 더 열심히 하게 만드는 댑 (DApp) 인 것이다.우리가 비록 두명밖에 없는 작은 팀이지만 제품 하나 만드는 솜씨는 솔직히 그 어떤 스타트업들과 비교해도 자신 있었기에 당시 현존하는 블록체인 기반 댑들 중에서 가장 수려한 인터페이스를 (그냥 우리끼의 착각일수도 있는) 자랑하는 제품을 선보였다는 자아도취감에 빠져 있었다.2018년 3월 5일에 발표한 런칭 공지 - Introducing Steemhunt: Daily ranking of effortlessly cool products fueled by STEEM blockchain그러나 (바로 스팀 커뮤니티를 정복할거라고 자신했던) 기대감과는 다르게 초기 3달간 유저는 50-100명 수준을 맴돌았다. 사실 지금에와서 생각해 보면 처음부터 유저가 급작스럽게 늘지 않고 아주 적은수의 열성 유저들로만 2-3개월을 보낸것이 현재 헌트 플랫폼으로 발전시키게 된 원동력이 되었다.이 초기 100명의 유저가 얼마나 열성적인 유저였냐면, 그 당시 우리가 보유한 스팀파워가 아주 초라한 수준이었기 때문에 스팀헌트에 열심히 헌팅한다고 아무런 돈도 되지 않던 그 시절, 매일같이 하루도 빠짐없이 제품을 발견해서 헌팅하고, 서로 발견한 제품들 토론하면서 재밌어하고, 심지어 우리가 부탁하지도 않았는데 알아서 우리 제품을 유투브, 레딧 등에 매일같이 홍보하는 100명의 유저가 생겼다.(스팀헌트 시작한 날부터 무려 1년 넘는 시간동안 하루도 안빠지고 유투브에 스팀헌트 관련 영상을 올려주는 유투버이다. 물론 하루에 제품도 2-3개씩 공유하는 열성 헌터이다.)3. 토큰 경제를 붙이면서 드디어 비상 - 전 세계 댑 순위 7위까지 등극그 당시 수 많은 ICO들이 "유틸리티" 토큰을 주장하며 모금했던 수십 수백억이 시장에서 증발하던 시기였다. 우린 이런 생각을 하기 시작했다. 사탕 사먹으라고 발행한 백원짜리 동전을 손에 쥔 백명의 사람들이 사실 사탕 사먹으려는게 아니고 모두 이백원, 삼백원에 팔기위해 손에 쥐고 있는 사람들로 채워지니 그놈의 "유틸리티"가 생길리가 있나...그래서 우리는 커뮤니티를 유지/발전시키는 핵심 활동들, 그리고 그 공헌도를 매일 정량화시켜 토큰 바운티 보상으로 결합시켜서 무려 1년간 토큰 유틸리티를 만드는 실험인 헌트 토큰 바운티 프로그램을 시작했다. 특히, 헌터 활동의 리워드 풀을 형성하기 위한 스팀파워 임대를 기반으로 헌트 토큰을 가치로 환산해서 스왑해주는 스폰서 프로그램도 같이 시작하였는데, 이게 스팀 커뮤니티에서 대 히트를 치면서, 정말 유저 그래프가 아래처럼 치솟는 경험을 하게 된다. 이 무렵 스팀잇 재단으로부터 그 당시 싯가로 10억이 넘는 금액인 백만 스팀파워를 임대 투자 받으면서 스팀헌트는 스팀 커뮤니티의 명실상부한 탑 10 댑 (DApp)의 지위를 얻게 된다. 특히 전 세계 약 2,600개의 댑들의 실제 트랜젝션 데이터를 기반으로 매일 랭킹이 매겨지는 권위있는 사이트인 스테이트오브더댑스 (State of the DApps)에서 2019년 1월에는 전체 7위를 하기도 했다. 이 후에도 항상 상위 20위권을 계속 유지중이다. 특히 도박, 게임류를 제외한 소셜부문은 전체 5위를 계속 유지중이다. 4. 고난의 길 - 어뷰저와의 반년간의 처절한 싸움사실 조금 극단적으로 말하면, 이걸 경험해 보지 않은 대다수의 리버스 ICO들은 단언컨데 토큰 경제를 붙이는 순간 폭망할 것이다. 왜냐면 어떤 서비스더라도 '보상'행위가 붙는 순간 시스템을 어뷰징해서 더 많은 보상을 타가고자 하는 지능적인 어뷰저들이 대거 달라붙게 되고, 이를 시스템적으로 개선하지 못하면 아무리 백만, 천만단위를 자랑하던 서비스더라도 유저들이 일장춘몽처럼 사라지게 된다.우리 역시 리워드 풀의 규모가 커지면서 대규모의 지능적인 어뷰저들의 공격을 받기 시작했다. 이들과 싸우는 처절한 전투 이야기를 여기서 다 풀면 글이 너무 길어지기에, 짧게 요약하면, 우리는 이들의 행위를 시스템적인 디텍션 알고리즘과 커뮤니티기반의 감시 시스템, 그리고 공헌도에 대해 상대적으로 검증하는 유저 스코어 시스템을 도입하여 스케일이 가능한 수준으로 발전시켰다. 지금은 우리의 이 노하우를 다른 스팀 댑들과도 공유하는 블랙리스트 / 화이트리스트 데이터베이스까지 운영할 정도로 우리의 토큰 모델은 다른 어떤 블록체인 기반 댑들이나 리버스 ICO 프로젝트들과 비교해도 월등한 수준이라 자신한다.https://github.com/Steemhunt/whitelist/blob/master/steemhunt/blacklist.json5. 덕후심을 메이커에게 팔 수 있는 토큰 경제 - 헌트 플랫폼으로 확장스팀헌트가 이제 월 6-10만 정도의 트래픽, 온체인에서 15,000명 이상의 헌터들이 활동하는 유저 기반이 쌓이고, 온-오프 체인 기반의 토큰 모델이 정교하게 결합된 헌트 토큰 경제를 운영하다 보니, 이제 판을 더 크게 키우고자 하는 포부가 생기게 되었다.특히, 그간 숱하게 생겼다 사라진 "리워드 기반의 보상형 소셜" 댑들의 가장 큰 문제는 바로 이건데,유저들이 벌은 저 토큰의 사용성은 그래서 무엇?이거에 대해 명확한 답을 제시할 수 있는 댑 프로젝트가 많지 않은게 현실이다. 우리는 이에대한 해답으로, 스팀헌트라는 순수 커뮤니티를 기반으로 이들의 덕후심, 즉 얼리어답터들의 테크 제품에 대한 지식, 열정, 전파력등을 기업들이 자유롭게 활용 가능한 인플루언서 기반의 거래 플랫폼으로 발전시키는 헌트 플랫폼 계획을 발표하였다.헌트 플랫폼은 크게 다음 세가지 레이어로 돌아가는 메이커와 테크 얼리어답터간의 연결 플랫폼이다.커뮤니티 레이어: 광고 모델이 필요 없는 자생가능한 테크 커뮤니티인 스팀헌트가 플랫폼 전체의 기반 레이어로서 얼리어답터를 생태계로 공급하는 역할을 담당한다.댑/서드파티 레이어: 테크 메이커가 얼리어답터들과 다양한 형태의 가치교환이 가능한 리뷰헌트, 아이디어헌트와 같은 댑이 운영됨으로써 토큰의 사용성을 제공한다.메이커/컴퍼니 레이어: 얼리어답터들의 전파력을 활용하여 신제품 런칭의 파급력을 높이고자 하는 테크 메이커들을 지속적으로 유입시킨다.즉, 요약하면 스팀헌트를 통해 꾸준히 유입되는 테크 덕후들을 기업들이 리뷰헌트를 통해 다양한 리뷰 캠페인 거래를 제안할 수 있고, 아이디어헌트를 통해 크라우드펀딩을 진행함으로써 그들의 신제품 런칭에 테크 덕후들을 엮어서 런칭 버즈를 최대화 할 수 있는 플랫폼이다.이렇게 기업들이 테크 덕후들의 자원을 활용하기 위해 헌트 토큰을 사용하고, 헌터들 역시 기업들이 리뷰를 위해 할인된 가격으로 판매하는 제품들을 구매하거나 크라우드펀딩에 참여하기 위해 헌트 토큰을 사용함으로써 헌트 토큰이 계속 순환되는 경제를 만들고자 함이다.6. 우리의 아주 현실적인 포부우리가 하려는 헌트 플랫폼은 사실 탈중앙화로 세상을 바꾸는 것도, 어려운 기반기술로 나같은 문돌이들은 1도 이해 못할 메인넷 비전을 팔려는 것도 아니다. 우리의 비전은 사실 아주 심플하다.기업들이 테크 덕후들을 활용하여 글로벌 단위의 제품 런칭 마케팅을 펼칠 수 있는 가장 쉬운 플랫폼 구축지금까지는 기업들이 이런 얼리어답터들을 타겟팅 하려면 레딧이나 프로덕헌트, 혹은 테크 리뷰어들을 일일이 찾아서 마케팅을 제안하는 방식이였다. 특히 레딧은 각 서브레딧마다 고유의 문화와 룰이 있기 때문에, 거기에서 열심히 활동한 사람이 아니면 절대 접근 불가능한 속성도 존재한다.헌트 플랫폼은 이런 테크 덕후들이 스팀헌트라는 놀이터에 모여있고, 기업들은 리뷰헌트를 통해 이들에게 자신들이 근거지로 활동하는 레딧, 해커뉴스, 유튜브 등 각 채널에서의 리뷰 마케팅을 제안하고, 아이디어 헌트를 통해 이들만을 위한 한정판 발매, 제품 우선권등을 거래할 수 있는 크라우드 펀딩이 결합되어, 기업 입장에서는 비교적 저렴한 자원으로 효율적인 런칭 마케팅을 진행할 수 있는 플랫폼을 만드는 것이 우리의 목표이다.7. 아주 현실적인 팀과 커뮤니티스팀헌트 팀은 사실 단 두명이다. 이 글을 쓰고 있는 내가 (조영휘) 디자인과 마케팅을 담당하고 있고, 다른 한명 (김동혁)이 혼자서 개발을 도맡아 하는 중이다. 우리가 굳이 이렇게 극단적인 린 팀 (Lean Team)을 운영하는 이유는 (돈이 모잘라서이기도 하지만) 팀은 유저 스케일이 커지면서 거기에 fit이 가장 맞는 사람으로 충원해야 한다는 철학이 있기 때문이다.솔직히 아직 제품도 없고 유저도 없는 팀이 벌써 CEO, CSO, COO, CTO등등 C 레벨만 5명 이상, 개발, 운영 포함 수십명짜리 팀을 구성하는건 우리 철학에 맞지 않는 방식이다. 유저 스케일이 커지게 되면 원래 설계했던 R&R이 180도 바뀌게 마련인데 이걸 미리 예측해서 팀을 짜는게 절대로 불가능하기 때문이다.그러나 하루 수백개의 제품이 공유되고 수만명의 헌터들의 커뮤니티 관리를 위해서는 당연히 대규모 인력이 필요할 수 밖에 없다. 그래서 우리가 고안한 방법은 커뮤니티 관리 역할을 커뮤니티에서 선출하여 운영하는 매니저, 모더레이터, 큐레이터 롤 이다.우선 팀 급의 인력은 위에 설명한 두명의 팀원에 커뮤니티에서 선출된 두명의 매니저를 충원하여 운영하고 있다. 여기에 더해 커뮤니티에서 선발된 총 10명의 모더레이터가 커뮤니티에 공유되는 모든 컨텐츠를 점검하고, 저작권 침해 가능성을 방지하는 역할을 하고, 큐레이션 기여도가 가장 높은 상위 20명이 매주 선발되 visibility가 저조한 우수 컨텐츠들을 발굴하여 추천하는 역할을 수행하고 있다.8. 우리는 제품 전문가입니다모든 팀이 각기 자신 있는 분야가 있듯이, 우리 스팀헌트 팀이 가장 자신 있는 부분은 "섹시한 제품"을 만드는 것이다. 그게 블록체인 기반이던 아니던 상관 없이, 우리가 지금까지 그래왔고, 앞으로도 집중할 부분은 실제 유저가 열광하게 만드는 제품을 만들어서 pump and dump에 기반한 가치가 아닌 실 유즈 케이스에 기반한 가치를 만드는 일이다.우리의 이런 여정에 함께할 투자자를 IEO (Initial Exchange Offering)을 통해 모집 중이고, 이미 지난 3월 14일 - 18일까지 IDCM에서 진행한 1차 IEO에서는 타겟 금액의 146% 이상이 모이면서 성공적으로 완판이 되었다.뭔가 기승전토큰세일홍보로 글이 귀결되는듯 하여 심히 미안한 마음이 들긴 하지만, 혹시라도 제품도 없이 출처 불명의 (혹은 성사 가능성이 모호한) 각종 파트너십, 협약 등으로 점철된 토큰 세일에 지쳐 뭔가 다른 프로젝트 투자처를 물색하고 계신 분이라면, 우리 프로젝트를 한번 살펴봐주길 바라는 마음에 우리 2차 세일즈에 대한 홍보를 하고자 하니, 이 홍보가 거북하신 분은 여기서 창을 닫아 주시면 감사하겠다.헌트 플랫폼의 2차 세일즈는 3월 22일 (금) 부터 26일 (화)까지 프로비트 거래소에서 진행될 예정이다. 특히 이번 세일즈에서는 IEO 최초로 스팀 토큰을 지원하는 점 때문에 스팀 커뮤니티에서도 큰 관심을 받고 있다.IEO 페이지 확인 - https://www.probit.kr/ko-kr/ieo/hunt-round1/0글로벌 프로젝트인 만큼, 우리 공식 채팅 채널들은 죄다 English-only로만 운영중이다. 이에 한국 투자자분들의 불편을 해소하고자 IEO를 위한 임시 카카오톡 채팅방도 운영중이다.https://open.kakao.com/o/g1odiHhb혹시 이 프로젝트가 진짜로 어떻게 돌아가고 있는지, 헌터들이 어떤 식으로 활동하고 다니는지를 알아보고 싶으신 분은 우리 공식 디스코드 채널에 조인하시면 모든 커뮤니티 활동을 모니터링 할 수 있다.https://discord.gg/Zda7Trs스팀헌트 프로젝트의 모든 공식 발표는 스팀헌트 스팀잇 블로그를 통해 이루어지는데 아쉽지만 영어로만 발표된다 (한글버전은 내 개인 스팀잇 블로그인 @project7을 통해 확인할 수 있다).https://steemit.com/@steemhunt
조회수 1095

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

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

회사에서 말 잘하는 프로또박이 되기

말이 많은 것과 말을 잘하는 것은 엄연히 다릅니다. 가끔 회사에는 프로또박이들이 한 분씩 계십니다. 그리 길게 말하는 것 같지도 않은데 뇌리에 타카를 쏜 것 마냥 상큼하게 메시지를 박아주시는 분들이죠. 깔끔하고 명료한데다가 뭔가 안경선배같은 아우라까지 풍기는 터라 선망의 대상이 되기도 합니다. 물론 말이라는 게 항상 또박또박일 필욘 없습니다. 매일 일상마다 또박또박 거리면 설명충같기도 하고, 재수없어 보이기도 하니까요. 스벅에서 친구와 해묵은 얘기를 나누거나 닭도리탕과 처음처럼을 마시며 노가리를 깔 때는 의식의 흐름이 더 중요합니다. 흔히 우리가 의식의 흐름이라고 부르는 대화의 기법은 '말꼬리잡기' 인데 이를테면 이런식입니다."어제 라면 먹었는데 눈이 부었다.""그러게 쌍꺼풀이 완전 없어졌네.""야 나 쌍꺼풀 수술해야 하지 않을까?""넌 쌍꺼풀이 문제가 아니다.""니 얼굴.""응 니 얼굴.""아 맞다, 너 내 친구 소개해주까?""뭐하는 사람인데?""뭐 디자인한다는 거 같던데.""아 디자인쪽 하는 분이면 야근많지않나? 자주 못보면 싫은데.""너도 야근많잖아.""아...진짜 요즘 것때문에 짜증나 죽겠다니까.""왜 또 팀장이 계속 꼰대짓해?""아니 세상에 있잖아....블라블라..."네 그렇습니다. 짧은 대화지만 눈이 부은 것에서 야근얘기로 넘어오게 되었습니다. 이러한 대화가 이어지는 것을 '의식의 흐름' 기법 내지는 '아무말 화법' 이라고 하죠. 그냥 생각나는 대로 마구 내뱉는 느낌이랄까요. 주로 친구와의 대화는 이런 식의 화법을 따릅니다.그러나 일할 때 이런식으로 말하다간 맴매맞겠죠.일할 때는 "또박이 화법"을 활용합니다. 또박이 화법은 상당히 어렵고 난해한 부분이 있어서 어떻게 정리를 해야할 지 꽤나 고민을 했습니다. 크게 3가지의 단계로 나눌 수 있겠더라구요. 일단 오늘은 기초편으로, 또박이의 기본중에 기본인 "끊어말하기" 에 대해 알아보도록 하겠습니다.제1장. 또박이의 외모1. 안경을 쓰자.안경을 쓰면 똑똑해 보입니다. 물론 안경을 썼을 때 아라리같다면 지양하도록 합시다. 추천드리는 포즈는 사카모토의 제스쳐입니다. 반무테는 늙어보이지만 똑똑해보이더군요. 코난안경은 코난같이 생겨야 하므로 패스합시다.사카모토입니다만?2. 올바른 자세.거북목에 뛰이.....해서 어깨 축 늘어뜨리고 있으면 또박또박한 말이 안나옵니다. 복화술 화법으로 입은 안벌리고 입술만 오물거리면 쭝얼쭝얼 거리는 듯 해서 별로입니다. 정석의 자세를 알려드리죠. 일단 제시카 챠스테인 누님의 미스슬로운 포즈로 변신해보도록 합시다. 고개는 집어넣고 여유로운 자세와 적당히 소매를 걷고 윗 단추를 풉니다. 아래와 같은 자세가 또박이의 정석이랄까요. 혹시라도 영어또박이를 하고 싶으시다면 미스슬로운을 200번쯤 재감상하시길 추천드립니다.챠스테인 누님 [미스 슬로운 中]3. 제스쳐는 단순하게.이렇게 하라는 건 아님스피치 학원가면 허리밑으론 손을 내리지 마라 짝다리 짚지마라 등등 다양한 제스쳐 룰을 알려주는데, 사실 이건 몸에 밴 습관인지라 어지간해선 고치기가 어렵습니다. 우리가 제기찰 때 왠지 손이 으에ㅞ에ㅞ? 처럼 되는 것과 비슷하달까요. 음, 제스쳐에서 중요한 건 손가락입니다. 검지가 괜히 Index finger가 아니죠. 손가락의 힘과 방향에 따라 집중력도 크게 좌우된답니다. 우리의 챠스테인 누님처럼 부드럽고 고결한 검지의 선을 만들 수 있다면 좋겠지만, 그게 아니라면 그냥 어딘가를 잡고 얘기하는 편이 나을 것 같습니다. 선이 살아있는 검지. 제2장. 또박이의 화법또박이의 기초예제부터 알아보겠습니다. 오늘은 3가지 예제를 보도록 하죠. 일단 말을 시작하는 '또박한 도입'부분을 알아볼까요? 뭔가 말을 시작할 땐 갑자기 끼어들면 안됩니다. 우리가 친구들과 얘기할 때도 '내가 재미있는 얘기 해줄까?'(물론 그것은 대부분 재미가 없음) 하면서 들어가듯 내가 지금부터 말을 하겠다는 뉘앙스의 스타트문장을 잘 얘기하는 것이 또박이의 첫걸음이더라구요.그런데 이 첫 문장이 "제가 의견을 말해도 되겠습니까?" 라는 식의 안경선배 말투면 가끔 어색해질 때가 있더라구요. 시공간이 일그러지는 듯한 느낌도 받고... 그래서 시공간의 균형을 중요시하는 분들께선 간단하게 다음과 같이 말하시더군요."제 생각은...(PAUSE)"이라고 말입니다. 아주 짧은 2초간의 포즈이지만, 이 효과는 굉장한 집중효과가 있습니다. 만약 상대방의 의견에 대한 반박이나 다른 인사이트를 말하고싶다면 어떻게 할까요? 마찬가지입니다. '제 생각은.' 입니다. 혹시라도 그 상대방이 나의 미래를 좌지우지 할 수 있는 존재이거나 뭔가 내 결재란 어딘가에 있는 이름이라고 한다면 "좋은 의견입니다. 하나 덧붙이자면..."이라고 그 의견이 좋든 안좋든 그냥 일단 좋은 의견입니다. 하나 덧붙... 이라고 얘기해주도록 합시다. 이 때도 ~덧붙이자면... 다음엔 2초 포즈를 걸어줍시다. 뭔가 집중되는 느낌과 함께 부담과 현기증을 동시에 느낄 수 있습니다. 근데 중요한 건 이렇게 시작을 했는데, 그 다음 말이 별 거 없다거나 횡설수설하면 '그건 어떤 혼돈의 음성이니?' 라는 눈빛세례를 받을 수 있습니다. 말을 하면서 생각하는 게 아니라, 생각하고 말을 하는 겁니다. 이 때 생각의 구조는 다음과 같습니다.1. 전제(-한다면)2. 가정(-입니다.)3. 누가/무엇을4. 어떻게5. 어쩐다.이렇게 5단계로 따박따박 얘기해줍니다. 경우에 따라 1,2번은 생략이 가능합니다. 주로 1,2번은 상대방의 의견을 다시 한 번 정리해주고 내 의견을 들어가는 경우에 많이 쓰이죠. 또는 현재 프로젝트의 상황을 정리하면서 내 의견의 거점을 확실히 잡는 역할두 하구요. 예를 들어볼께요."현재 오프라인의 사용자가 온라인 사용자보다 훨씬 많은 상태인데, 만약 오프라인에 별다른 공지없이 온라인을 바로 오픈하게 된다면 고객들이 혼란스러워하거나 변화된 UX에 대한 학습을 강요받게 될 가능성이 있습니다. / 일단, 리뉴얼하는 웹페이지 이벤트를 온라인에선 헤드배너, 이벤트 지점안내를 진행하고 오프라인에선 방문고객 대상 결제 시 안내를 통해 옴니채널로 운영하면서 안정적으로 리뉴얼페이지로 유도하면 어떨까 하는 생각입니다."전제 : 현재 오프라인의 사용자가 온라인 사용자보다 훨씬 많은 상태인데, 만약 오프라인에 별다른 공지없이 온라인을 바로 오픈하게 된다면 / 가정 : 고객들이 혼란스러워하거나 변화된 UX에 대한 학습을 강요받게 될 가능성이 있습니다.무엇을 : 일단, 리뉴얼하는 웹페이지 이벤트를 / 어떻게 : 온라인에선 헤드배너, 이벤트 지점안내를 진행하고 오프라인에선 방문고객 대상 결제 시 안내를 통해 옴니채널로 운영하면서 / 어쩐다 : 안정적으로 리뉴얼페이지로 유도하면 어떨까 하는 생각입니다.네 이런 식으로 포인트 단어들만 묶어도 말이 되게끔 논리구조를 만드는 거죠. 저 문장의 핵심은 결국"웹이벤트를 옴니채널로 운영해서 오프라인 고객들도 유도하자."라는 한 문장으로 요약할 수 있겠네요. 대부분 위 5가지 요소에서 하나씩 빠질 때마다 반문과 질문이 생기게 되는데, 그걸 물어봐주는 사람은 오히려 괜찮은 편이예요. 일반적으론 그냥 '뭔 말이야?' 하고 말아버리죠. 한 번 볼까요.일단 전제가 빠지면 "쌩뚱맞다." 라는 생각이 들 수 있습니다. 가정이 없으면 해결해야 할 문제점이 명확히 보이지 않아  "추상적이다." 라는 느낌을 주죠. 주어가 없으면 "그러니까 뭐슬?" 이라는 반문이 나옵니다. 어떻게가 없으면 "말을 해 말을." 이라는 반응이 나오고, 어쩐다..라는 내용이 없으면 "어쩌라고?" 라는 질문이 튀어나와요.여기서 특히 중요한 건 제일 마지막에...그러니까 그걸 어쩌라고? 라는 부분을 콕 찝어주는게 중요합니다. 유도하자!제작하자!공유하자!런칭하자!모집하자!등등... 딱 하나의 행위로 점철될 수 있는 명확한 단어로 정리해주는 게 또박이의 첫 걸음입니다. 저 부분이 없으면..이렇게 될 수 있어요."그래서...그 옴니채널로 운영을..뭐 잘 해보면 어떨까 해서요..."잘한다, 가치있게 해보자, 정리해보자....등등의 추상적인 단어들로 헤벌레 풀어질 수 있죠. 그러니 마지막에 확실한 서술어로 콱 쪼매주어야 해요.마지막 또박이의 기초화법은 바로 말의 마무리입니다. 위에서 말한 마지막 '어쩌라고' 부분에 대한 얘기와 일맥상통합니다. 말이 어버버버 해지는 이유는 그 내용과 논리성때문입니다. 그러나 내용이 챡챡 정리되어 있어도 '어미처리'가 흐릿하면 느낌적으로 말이 장황해보이죠.말을 마무리 지을 때"그렇다고 생각은 하는데..아닐 수도 있구요...""그러는게 어떨까하는 생각이 들기도 합니다.""이게 맞는지는 모르겠지만...""그렇지 않을까...해서요."등등 어미를 주욱 늘여버리는 경우가 종종있는데. 물론 이는 내 생각에 대한 확신을 너무 뿜뿜하면 재수없는 놈이 될까봐 자기방어에서 비롯된 화법일 겁니다. 살아남아야 하니 어쩔 수 없죠. 하지만 인생은 원래 개썅마이웨이이므로 저렇게 말해도 욕먹고, 따박하게 말해도 욕먹습니다. 기왕 욕먹을 거면 어버버 해보이기보단 좀 쎄보이는 편이 낫지 않을까요?그렇다고 정치인마냥 부르짖으란 얘기는 아니고, 다음과 같은 어미처리의 느낌이랄까요."~ 라고 생각합니다.""~의 방법도 있습니다.""~쪽을 추천합니다.""~해보는 건 어떨까요."등등 아무리 풀어도 2어절 이상을 넘기지 않는 우회적 어미처리를 추천드립니다. 내가 진리요 생명이다라는 느낌보단 내 생각은 확고하지만 난 자비롭다라는 느낌을 동시에 줄 수 있는 크세르크세스식 화법입니다. 유용하게 쓰이곤 하더군요.응용편에서 계속.
조회수 1105

챌린저스가 만난 사람들

나쁜 습관을 하나 없애면 새로운 습관이 생겨나요.결국 빈자리를 채우게 마련이거든요이름 차예진직업 플로리스트좋아하는 습관 아침일찍 일어나 팟캐스트 듣기저는 대전에서 플로리스트로 활동하고 있어요. 자유도가 높은 직업이다보니 스스로의 생활을 관리하고 챙기는 것이 중요해요. 몇시에 일어나고 몇시까지 어디에 가야한다와 같은 규칙적인 리듬의 생활이 필요하기도 해요. 바쁜 일정들을 하나씩 깨나갈 때, 주도적이고 적극적으로 살고 있다는 느낌을 받게되요.어떤 계기로 챌린저스 앱을 사용하시게 되었나요?우연히 6시 기상이벤트 광고를 보게되었어요. 사실 원래 아침 6시에 일어나고 있던 건 아니었어요. 늘 생각만 하고 있던 목표였죠. 그래서 조금 망설여졌어요. 내가 과연 이 미션을 잘 달성할 수 있을까. 돈만 걸었다가 잘 못하면 어쩌지. (웃음). 그래도 한번 해봐야겠다 생각했어요. 매번 일찍 일어나겠다고 생각만 한 가득하고 있었는데, 이 참에 한 번 작은 도전을 즐겨보자는 생각으로 챌린지를 신청했어요.챌린지 첫 날, 6시에 눈이 딱 떠졌어요. 정말 신기하더라구요. 벌떡 일어나서 오늘의 미션을 하기 위해 책상으로 가서 오늘의 한마디를 적었어요. 뭘 써야할까 머리를 막 굴리다보니 잠이 깨더라구요. 정말 신기한 경험이었어요. 그렇게 2주 동안 매일 눈이 떠지더라고요. 갑작스럽게 일찍 일어나려니 힘들지 않으셨나요?그게 그래야 하는데, 이상하게 기분이 계속 좋았어요. 성취감이라고 해야할까. 사실 6시에 일어나는 게 무슨 대단한 업적은 아니잖아요. 근데 하루의 첫 목표를 잘 달성하고 나니까 자신감도 생기고 더 긍정적인 감정을 느꼈어요. 전날 회식을 가더라도 술을 마시지 않을 당당한 이유도 생기고, 생활 속에 작은 목표가 있으니 집중도 하게되고 좋더라구요. 그리고 무엇보다 아침에 손글씨로 한 마디를 적는 것이 기억에 남아요. '오늘 하루도 화이팅' 일어나자마자 이런 긍정적인 말들을 손으로 적으니 하루 종일 그 기운이 퍼져 있는 것 같았어요.평소에도 계획한 것은 빠짐없이 지키는 스타일인가요?꼭 그렇지는 않아요. 말씀드렸잖아요 6시에 일어나야지 생각만해왔다고. (웃음).그래도 꾸준히 스스로를 계발하려고 노력하는 편이라고 생각해요. 제가 매주 2개의 주간지를 구독해서 보고 있는데, 재즈 피플과 매경이코노미예요. 재즈는 제가 플로리스트로 활동하는 데에 좋은 영감을 많이 불어 넣어줘요. 규율이 있는 듯 자유분방한 그 느낌을 작업할 때도 많이 추구하게 되요. 평소에도 그 느낌을 놓치고 싶지 않아서 자주 꺼내보고 있어요. 매경은 경제와 세상 공부를 위해서 보고 있어요. 사실 경제 기사가 재미있지는 않거든요. 그럼에도 봐야겠다는 생각이 들어서 보고 있는 걸 보면, 필요하다고 생각하는 일은 실천하는 편인 것 같아요.예진님을 행복하게 만드는 습관이 있나요?저는 아침에 일어나서 팟캐스트 듣는 걸 좋아해요. 사실 이름도 잘 모르는데, 최신 경제 기사를 한 번 쭉 훑어주는 채널이예요. 팟캐스트는 꼭 집중해서 듣지 않고 배경 음악처럼 깔아두는데, 어쩌다 관심이 생기는 기사가 생기면 귀를 쫑긋하고 열심히 듣게되요. 그런 여유가 좋아요. 억지로 꼭 기억하려고 하면 하기 싫어지잖아요. 오히려 있는 듯 없는 듯 틀어만 두고 가끔 관심을 가지게 되면 그런 지식들이 천천히 삶에 배어들어와요. 자주 접하고 친해지는 과정에서 쌓인 친근감 덕분에 관심 영역이 넓어지는 것 같아요. 경제라는 딱딱하고 어려운 내용에 친해진 것도 팟캐스트를 통해서였어요. 처음에는 재미가 없었죠. 용어도 낯설고, 무언가 거창한 이야기 같고. 그러다 출근 준비를 하면서 몇 번 무릎을 탁 친 적이 있어요. '아 그래서 그런거구나' 하고 생활에 스며들어 있는 경제상식에 대해서 이해를 하게 된거죠. 그런 재미가 쌓이다 보니 지금은 매일 빼먹지 않고 습관처럼 듣게되요. 그럼 사람들에게 추천하고 싶은 습관도 있나요?저는 집에서 TV 를 없앴어요. 사람들이 많이 시간을 보내는 것은 TV와 휴대폰 두 개 예요. 거의 25년을 봐왔는데, 딱히 어떤 프로그램을 정해놓고 보는 것도 아니었어요. 말 그대로 TV를 틀어놓고 살았는데, 어느 순간 이건 아니다 싶은 생각이 들었어요. 사람의 변화라는 게 남들이 아무리 뭐라고 이야기해도 찾아오지 않거든요. 그러다 어느 한 순간 이대로는 안되겠어 싶으면 사람들은 변하게되요. 저는 그런 생각이 찾아오자마자 TV 를 버렸어요. 처음에는 후회가 됐죠. 집 안이 텅 빈 것이 허전하기도 하구요. 그런데 그 덕분에 주간지도 볼 수 있게 되고 새로운 컨텐츠에 관심도 갖게 되었어요. 빈자리는 결국 채워지기 마련이거든요. 한 행동을 줄이면 자연스럽게 다른 행동을 더 하고 싶어져요. TV를 버린 덕분에 관심사가 많이 늘어나게 된 것 같아요.새해에 이루고 싶은 꿈이나 목표가 있으신가요?올 해는 잘 정리하는 습관을 들이려고 해요. 평소 쓰는 물건들을 제자리에 놓아두는 것 뿐만 아니라 필요없는 물건들을 하나씩 버림으로써 생활을 단순하게 만들 생각이예요. 그리고 예쁜 꽃들로 사람들에게 행복감을 주는 그런 선물을 계속 만들어 나가고 싶어요. 컨텐츠 보는 것도 빠짐없이 계속 할 예정이구요. 챌린저스 브런치가 있는 줄 몰랐는데, 꼭 구독하도록 할게요 (웃음) 말해놓고 보니 할 게 너무 많은데, 이걸 다 챌린지로 만들어주실 수 있나요?사람들이 아무리 몰아세워도 바뀌지 않아요.그러다 한 순간 '이대로 안되겠다' 싶을때 그 때 사람이 변해요.결국 스스로가 깨달아야죠좋은 습관을 가진 사람들의 이야기interviewee 차예진interviewer 김왕수www.chlngers.com
조회수 1087

첫번째 편지

아래 메일은 3월 말에 8퍼센트 프로덕트팀 분들께 보낸 첫 번째 편지입니다. 메일을 쓸 때의 마음을 잊지 않고 약속을 지키고자 공개해 둡니다.안녕하세요? 원우님, 연태 님, 부(혜은)님, 문수님, 진님, 보영님, 해원님.(이름의 순서는 오늘 밤 제 기분에 따라 랜덤으로 정해졌습니다. 신경 쓰지 마세요)여러분들께 보내는 첫 번째 메일입니다. 반갑죠? 아기를 재우다 보니 늦은 밤이 되어 버려서 연애편지를 쓰고 싶어 졌습니다.현재 저를 포함하면 우리 팀은 8명이고, 한 주 뒤에 세 분이 더 오시면 이제 팀은 11명이 됩니다. 놀라운 일입니다. 채용을 위해 사람을 만나다 보니 지금 우리 팀에 대해서도 많은 것을 생각해 보게 됩니다. 우리 팀 어떤 것 같으세요? 저는 정말 좋은 팀이라고 생각합니다.다양한 곳에서 다양한 경험을 한 사람들이 모여 있습니다. 서로 간의 커뮤니케이션을 즐거워합니다.좋은 제품을 만들어 내기 위한 생산적인 토론을 합니다. 자기 일보다 다른 사람의 일을 우선시합니다.각 개인의 능력이 훌륭합니다. 어때요? 동의하시나요? (네!) 제가 여러분께 해드릴 수 있는 것이 많지 않습니다만, 그중 제일 중요한 것은 여러분이 좋은 팀에서 일할 수 있도록 하는 것입니다.좋은 분을 채용해서 여러분이 서로에게 자극받고 발전할 수 있도록 하고 싶습니다.  그렇게 모인 좋은 분들이 자신의 능력을 충분히 발휘하고 최대한의 시너지를 낼 수 있도록 환경과 문화를 만들어 가는 일이 제가 해야 할 일입니다.우리 손으로 만든 제품을 통해 1000명에 가까운 사람들에게 170억이 넘는 돈이 전달되었습니다. 하루에 1억이 넘는 돈이 여러분이 만든 제품을 통해 중개되고 있습니다.그리고 올해 말에는 이 숫자의 자릿수가 달라질 것입니다. 대단하죠?방금 캡처한 첫 페이지. 저 숫자도 이제 과거가 되었습니다우리는 "사용자가 필요로 하는" "목적이 분명한" “하나"의 제품을 만들고 있습니다. 이것 또한 행복한 일입니다. 우리의 세계에서 내가 기획한 것, 디자인한 것, 개발한 것이 그냥 사라져 버리는 경우는 수도 없이 많습니다. 하지만 우리가 만들고 있는 것은 사람들이 꼭 필요로 하는 것이고 여러분들의 노력은 빛나는 제품이 될 것입니다. 지금까지 우리가 만들어온 제품에 자부심을 가져주세요. 그리고 앞으로 우리가 만들어갈 제품에 그 자부심을 담아 주세요.마지막으로 여러분 각 개인이 가진 꿈과 목표를 놓지 말아 주세요. 회사의 성공 재료로 여러분의 열정이 소모되는 것이 아닌, 여러분 이상의 실현을 통해 회사가 성공하길 바랍니다. 자신의 방향과 회사의 방향이 일치하지 않는다고 판단되면 참거나 기다리지 말고 그 두 가지를 일치시키기 위한 최대한의 노력을 해주세요. 회사의 방향도 충분히 바뀔 수 있습니다.고마워요. 다들. 내일 저를 만나거든 이 메일에 관한 이야기는 말아주세요. 이런 말들을 직접 하기 힘들어서 메일로 쓰는 거니까요.안녕!#8퍼센트 #에잇퍼센트 #팀워크 #조직문화 #기업문화 #팀문화 #팀플레이 #협동 #편지 #초심
조회수 4656

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

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

네이버 신디케이션 — Rails

블로그에 새 글이 올라올 때, naver에 사이트 등록을 한다. 네이버 신디케이션 API를 이용하면 자동으로 등록된다.Wordpress에는 네이버 신디케이션 plugin이 존재한다. Rails gem을 찾아보니 애석하게도 없었다. 직접 만들면서 알게 되었다. 딱히 gem을 만들 만한 일도 아니더라.네이버 신디케이션을 이용하려면 우선 네이버 웹마스터 도구를 이용해야 한다. 해당 url이 자기 것이라는 인증과정만 거치면 바로 사용할 수 있다.작동방법은 대강 이렇다.네이버 신디케이션 API를 이용해서, 새로운 글이 생성되었음을 알린다. (혹은 글이 지워졌음을)네이버 크롤링 봇, Yeti가 와서 크롤링 해간다.API를 이용할 때 미리 약속된 format으로 만들어야 되는데, ATOM feed와 구조가 거의 같다. 다만 네이버가 정한 룰 때문에 (꼭 이름/저자/업데이트날짜 이런 순서를 지켜야 한다.)Rails에서 제공하는 atom_feed helper를 그대로 이용할 수 없다. 그러나 format만 살짝 바꾸면 되기 때문에 atom_feed helper를 이용해서, feed를 만드는 방법을 알려주는 Railscast가 늘 그렇듯 엄청 도움이 된다.(요즘 새로운 episode가 안올라오고 있는데… 힘내시라는 의미에서 예전에 유료결제 해드렸다)atom_feed helper의 코드를 그대로 가져와서 formating만 바꾼 naver_atom_feed helper를 만들었다. 별다른 건 없고, feed option 초기화 부분과 제일 마지막에 나와야 되는 link 부분을 주석처리한게 전부다.module NaverSyndicationHelper def naver_atom_feed(options = {}, █) ... feed_opts = {} //feed_opts = {"xml:lang" => options[:language] || "en-US", "xmlns" => 'http://www.w3.org/2005/Atom'} ... xml.feed(feed_opts) do xml.id... // xml.link... // xml.link... yield ActionView::Helpers::AtomFeedHelper::AtomFeedBuilder.new(xml, self, options) end end end새로만든 naver_atom_feed helper를 이용해서, feed부분만 완성한 code이다.naver_atom_feed({xmlns: "http://webmastertool.naver.com", id: 'http://ikeaapart.com'}) do |feed| feed.title "이케아아파트" feed.author do |autor| autor.name("이케아아파트") end feed.updated Link.maximum(:updated_at) feed.link(:rel => 'site', :href => (request.protocol + request.host_with_port), :title => '이케아아파트')이제 entry쪽을 만들어야 되는데, 네이버가 지정한 순서에 맞아야지만 신디케이션 서버에 전달할 수 있다. 정말 이상한 형식이다. 아무튼 그래서 Rails에서 제공하는 entry method를 사용하지 못한다. 이번엔 AtomFeedBuilder class에 naver_entry method를 만들었다.#config/initializers/feed_entry_extentions.rbmodule ActionView module Helpers module AtomFeedHelper class AtomFeedBuilder def naver_entry(record, options = {}) @xml.entry do @xml.id... # if options[:published]... # @xml.published(...) # end # if options[:updated]... # @xml.updated(...) # end # @xml.link(..) ...이번에도 순서 때문에 주석처리 한 것 밖에 없다. naver_entry method를 이용해서 완성된 코드가 아래 코드이다.# views/links/show.atom.buildernaver_atom_feed({xmlns: "http://webmastertool.naver.com", id: 'http://ikeaapart.com'}) do |feed| feed.title "이케아아파트" feed.author do |autor| autor.name("이케아아파트") end feed.updated Link.maximum(:updated_at) feed.link(:rel => 'site', ...) feed.naver_entry(@link, {id: link_url(@link)}) do |entry| entry.title(@link.title) entry.author do |author| author.name("이케아아파트") end entry.updated(@link.updated_at.xmlschema) entry.published(@link.created_at.xmlschema) entry.link(:rel => 'via', :href => (request.protocol + request.host_with_port)) entry.content(@link.contents) end end이제 새 글이 만들어 질 때, 이 atom 파일 주소를 네이버 신디케이션 API로 보내주면 된다. 참고로 Rails에서는 어떤 view파일을 사용할지 알아서 해주니, controller에 따로 ‘response_to’ 를 이용해서 format을 나눠줄 필요는 없고, 이름만 잘 맞춰주면 된다. (위 파일명은 show.atom.builder 이다)네이버 신디케이션 API에 핑을 보내는 code이다. 네이버가 지정해 놓은 header를 설정해 줘야 되고, 신디케이션 인증 토큰을 받아서 header에 넣어줘야 된다. 신디케이션 토큰은 네이버 웹마스터 페이지에서 볼 수 있다.require 'net/http' ... header = {"User-Agent"=>"request", "Host"=>"apis.naver.com", "Progma"=>"no-cache", "Content-type"=>"application/x-www-form-urlencoded", "Accept"=>"*/*", "Authorization"=>"Bearer " + ENV["NAVER_SYNDICATION_TOKEN"]} uri = URI.parse('https://apis.naver.com/crawl/nsyndi/v2') http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true args = {ping_url: link_url(link_id, format: "atom")} uri.query = URI.encode_www_form(args)request = Net::HTTP::Post.new(uri.request_uri, header) http.request(request)네이버 신디케이션 페이지에서 핑이 제대로 도달하는지 바로 확인해 볼 수 있다.#티엘엑스 #TLX #BA #BusinessAnalyst #비즈니스애널리스트 #꿀팁 #인사이트 #조언
조회수 1090

AWS Batch 사용하기

OverviewAWS Batch는 배치 컴퓨팅 작업을 효율적으로 실행할 수 있게 도와줍니다. 배치 작업량과 리소스 요청을 기반으로 최적의 리소스 수량 및 인스턴스 유형을 동적으로 프로비져닝합니다. AWS Batch에서는 별도의 관리가 필요 없기 때문에 문제 해결에 집중할 수 있습니다. 별도의 추가 비용은 없습니다. 배치 작업을 저장 또는 실행할 목적으로 생성된 AWS 리소스(인스턴스 등)에 대해서만 비용을 지불하면 됩니다. 이번 포스팅에서는 간단한 튜토리얼로 AWS Batch 사용 방법을 크게 11개의 Step으로 알아보겠습니다. 이렇게 진행하겠습니다.AWS에서 제공하는 Dockerfile, fetch&run 스크립트 및 myjob.sh 다운로드Dockerfile를 이용하여 fetch&run 스크립트를 포함한 Docker 이미지 생성생성된 Docker 이미지를 ECR(Amazon Elastic Container Registry)로 푸쉬간단한 샘플 스크립트(myjob.sh)를 S3에 업로드IAM에 S3를 접속 할 수 있는 ECS Task role 등록Compute environments 생성Job queues 생성ECR을 이용하여 Job definition 생성Submit job을 통해 S3에 저장된 작업 스크립트(myjob.sh)를 실행하기결과 확인 STEP1. AWS에서 제공하는 Dockerfile, fetch&run 스크립트 및 myjob.sh 다운로드AWS Batch helpers페이지에 접속합니다.    2. /fetch-and-run/에서 Dockerfile, fetchandrun.sh, myjob.sh 다운로드합니다.STEP2. Dockerfile을 이용하여 fetch&run 스크립트를 포함한 Docker 이미지 생성Dockerfile을 이용해서 Docker 이미지를 빌드합니다.잠시 Dockerfile의 내용을 살펴보겠습니다.FROM amazonlinux:latestDocker 공식 Repository에 있는 amazonlinux 의 lastest 버젼으로 빌드RUN yum -y install which unzip aws-cliRUN을 통해 이미지 빌드 시에 yum -y install which unzip aws-cli를 실행ADD fetch_and_run.sh /usr/local/bin/fetch_and_run.shADD를 통해 Dockerfile과 같은 디렉토리에 있는 fetch_and_run.sh를 /usr/local/bin/fetch_and_run.sh에 복사 WORKDIR /tmp컨테이너가 동작할 때 /tmp를 기본 디렉토리로 설정USER nobody컨테이너 실행 시 기본 유저 설정 ENTRYPOINT [“/usr/local/bin/fetch_and_run.sh”]컨테이너 실행 시 /usr/local/bin/fetch_and_run.sh를 call shell에 docker 명령을 통해 이미지 생성shell : docker build -t fetch_and_run . 실행하면 아래와 같은 결과가 출력됩니다.[ec2-user@AWS_BRANDI_STG fetch-and-run]$ docker build -t fetch_and_run . Sending build context to Docker daemon 8.192kB Step 1/6 : FROM amazonlinux:latest latest: Pulling from library/amazonlinux 4b92325dc37b: Pull complete Digest: sha256:9ee13e494b762db41b9db92a200f6784b78da5ac3b0f974fb1c38feb7f636474 Status: Downloaded newer image for amazonlinux:latest ---> 81bb3e78db3d Step 2/6 : RUN yum -y install which unzip aws-cli ---> Running in 1f5293a2294d Loaded plugins: ovl, priorities Resolving Dependencies --> Running transaction check ---> Package aws-cli.noarch 0:1.14.9-1.48.amzn1 will be installed --> Processing Dependency: python27-jmespath = 0.9.2 for package: aws-cli-1.14.9-1.48.amzn1.noarch --> Processing Dependency: python27-botocore = 1.8.13 for package: aws-cli-1.14.9-1.48.amzn1.noarch --> Processing Dependency: python27-rsa >= 3.1.2-4.7 for package: aws-cli-1.14.9-1.48.amzn1.noarch --> Processing Dependency: python27-futures >= 2.2.0 for package: aws-cli-1.14.9-1.48.amzn1.noarch --> Processing Dependency: python27-docutils >= 0.10 for package: aws-cli-1.14.9-1.48.amzn1.noarch --> Processing Dependency: python27-colorama >= 0.2.5 for package: aws-cli-1.14.9-1.48.amzn1.noarch --> Processing Dependency: python27-PyYAML >= 3.10 for package: aws-cli-1.14.9-1.48.amzn1.noarch --> Processing Dependency: groff for package: aws-cli-1.14.9-1.48.amzn1.noarch --> Processing Dependency: /etc/mime.types for package: aws-cli-1.14.9-1.48.amzn1.noarch ---> Package unzip.x86_64 0:6.0-4.10.amzn1 will be installed ---> Package which.x86_64 0:2.19-6.10.amzn1 will be installed --> Running transaction check ---> Package groff.x86_64 0:1.22.2-8.11.amzn1 will be installed --> Processing Dependency: groff-base = 1.22.2-8.11.amzn1 for package: groff-1.22.2-8.11.amzn1.x86_64 ---> Package mailcap.noarch 0:2.1.31-2.7.amzn1 will be installed ---> Package python27-PyYAML.x86_64 0:3.10-3.10.amzn1 will be installed --> Processing Dependency: libyaml-0.so.2()(64bit) for package: python27-PyYAML-3.10-3.10.amzn1.x86_64 ---> Package python27-botocore.noarch 0:1.8.13-1.66.amzn1 will be installed --> Processing Dependency: python27-dateutil >= 2.1 for package: python27-botocore-1.8.13-1.66.amzn1.noarch ---> Package python27-colorama.noarch 0:0.2.5-1.7.amzn1 will be installed ---> Package python27-docutils.noarch 0:0.11-1.15.amzn1 will be installed --> Processing Dependency: python27-imaging for package: python27-docutils-0.11-1.15.amzn1.noarch ---> Package python27-futures.noarch 0:3.0.3-1.3.amzn1 will be installed ---> Package python27-jmespath.noarch 0:0.9.2-1.12.amzn1 will be installed --> Processing Dependency: python27-ply >= 3.4 for package: python27-jmespath-0.9.2-1.12.amzn1.noarch ---> Package python27-rsa.noarch 0:3.4.1-1.8.amzn1 will be installed --> Processing Dependency: python27-pyasn1 >= 0.1.3 for package: python27-rsa-3.4.1-1.8.amzn1.noarch --> Processing Dependency: python27-setuptools for package: python27-rsa-3.4.1-1.8.amzn1.noarch --> Running transaction check ---> Package groff-base.x86_64 0:1.22.2-8.11.amzn1 will be installed ---> Package libyaml.x86_64 0:0.1.6-6.7.amzn1 will be installed ---> Package python27-dateutil.noarch 0:2.1-1.3.amzn1 will be installed --> Processing Dependency: python27-six for package: python27-dateutil-2.1-1.3.amzn1.noarch ---> Package python27-imaging.x86_64 0:1.1.6-19.9.amzn1 will be installed --> Processing Dependency: libjpeg.so.62(LIBJPEG_6.2)(64bit) for package: python27-imaging-1.1.6-19.9.amzn1.x86_64 --> Processing Dependency: libjpeg.so.62()(64bit) for package: python27-imaging-1.1.6-19.9.amzn1.x86_64 --> Processing Dependency: libfreetype.so.6()(64bit) for package: python27-imaging-1.1.6-19.9.amzn1.x86_64 ---> Package python27-ply.noarch 0:3.4-3.12.amzn1 will be installed ---> Package python27-pyasn1.noarch 0:0.1.7-2.9.amzn1 will be installed ---> Package python27-setuptools.noarch 0:36.2.7-1.33.amzn1 will be installed --> Processing Dependency: python27-backports-ssl_match_hostname for package: python27-setuptools-36.2.7-1.33.amzn1.noarch --> Running transaction check ---> Package freetype.x86_64 0:2.3.11-15.14.amzn1 will be installed ---> Package libjpeg-turbo.x86_64 0:1.2.90-5.14.amzn1 will be installed ---> Package python27-backports-ssl_match_hostname.noarch 0:3.4.0.2-1.12.amzn1 will be installed --> Processing Dependency: python27-backports for package: python27-backports-ssl_match_hostname-3.4.0.2-1.12.amzn1.noarch ---> Package python27-six.noarch 0:1.8.0-1.23.amzn1 will be installed --> Running transaction check ---> Package python27-backports.x86_64 0:1.0-3.14.amzn1 will be installed --> Finished Dependency Resolution Dependencies Resolved ================================================================================ Package                              Arch   Version            Repository                                                                           Size ================================================================================ Installing:  aws-cli                              noarch 1.14.9-1.48.amzn1  amzn-main 1.2 M  unzip                                x86_64 6.0-4.10.amzn1     amzn-main 201 k  which                                x86_64 2.19-6.10.amzn1    amzn-main  41 k  Installing for dependencies:  freetype                             x86_64 2.3.11-15.14.amzn1 amzn-main 398 k  groff                                x86_64 1.22.2-8.11.amzn1  amzn-main 1.3 M  groff-base                           x86_64 1.22.2-8.11.amzn1  amzn-main 1.1 M  libjpeg-turbo                        x86_64 1.2.90-5.14.amzn1  amzn-main 144 k  libyaml                              x86_64 0.1.6-6.7.amzn1    amzn-main  59 k  mailcap                              noarch 2.1.31-2.7.amzn1   amzn-main  27 k  python27-PyYAML                      x86_64 3.10-3.10.amzn1    amzn-main 186 k  python27-backports                   x86_64 1.0-3.14.amzn1     amzn-main 5.0 k  python27-backports-ssl_match_hostname                                       noarch 3.4.0.2-1.12.amzn1 amzn-main  12 k  python27-botocore                    noarch 1.8.13-1.66.amzn1  amzn-main 4.1 M  python27-colorama                    noarch 0.2.5-1.7.amzn1    amzn-main  23 k  python27-dateutil                    noarch 2.1-1.3.amzn1      amzn-main  92 k  python27-docutils                    noarch 0.11-1.15.amzn1    amzn-main 1.9 M  python27-futures                     noarch 3.0.3-1.3.amzn1    amzn-main  30 k  python27-imaging                     x86_64 1.1.6-19.9.amzn1   amzn-main 428 k  python27-jmespath                    noarch 0.9.2-1.12.amzn1   amzn-main  46 k  python27-ply                         noarch 3.4-3.12.amzn1     amzn-main 158 k  python27-pyasn1                      noarch 0.1.7-2.9.amzn1    amzn-main 112 k  python27-rsa                         noarch 3.4.1-1.8.amzn1    amzn-main  80 k  python27-setuptools                  noarch 36.2.7-1.33.amzn1  amzn-main 672 k  python27-six                         noarch 1.8.0-1.23.amzn1   amzn-main  31 k Transaction Summary ================================================================================ Install 3 Packages (+21 Dependent packages) Total download size: 12 M Installed size: 51 M Downloading packages: -------------------------------------------------------------------------------- Total 1.0 MB/s | 12 MB 00:12 Running transaction check Running transaction test Transaction test succeeded  Running transaction   Installing : python27-backports-1.0-3.14.amzn1.x86_64                    1/24   Installing : python27-backports-ssl_match_hostname-3.4.0.2-1.12.amzn1    2/24   Installing : python27-setuptools-36.2.7-1.33.amzn1.noarch                3/24   Installing : python27-colorama-0.2.5-1.7.amzn1.noarch                    4/24   Installing : freetype-2.3.11-15.14.amzn1.x86_64                          5/24   Installing : libyaml-0.1.6-6.7.amzn1.x86_64                              6/24   Installing : python27-PyYAML-3.10-3.10.amzn1.x86_64                      7/24   Installing : mailcap-2.1.31-2.7.amzn1.noarch                             8/24   Installing : python27-ply-3.4-3.12.amzn1.noarch                          9/24   Installing : python27-jmespath-0.9.2-1.12.amzn1.noarch                  10/24   Installing : python27-futures-3.0.3-1.3.amzn1.noarch                    11/24   Installing : python27-six-1.8.0-1.23.amzn1.noarch                       12/24   Installing : python27-dateutil-2.1-1.3.amzn1.noarch                     13/24   Installing : groff-base-1.22.2-8.11.amzn1.x86_64                        14/24   Installing : groff-1.22.2-8.11.amzn1.x86_64                             15/24   Installing : python27-pyasn1-0.1.7-2.9.amzn1.noarch                     16/24   Installing : python27-rsa-3.4.1-1.8.amzn1.noarch                        17/24   Installing : libjpeg-turbo-1.2.90-5.14.amzn1.x86_64                     18/24   Installing : python27-imaging-1.1.6-19.9.amzn1.x86_64                   19/24   Installing : python27-docutils-0.11-1.15.amzn1.noarch                   20/24   Installing : python27-botocore-1.8.13-1.66.amzn1.noarch                 21/24   Installing : aws-cli-1.14.9-1.48.amzn1.noarch                           22/24   Installing : which-2.19-6.10.amzn1.x86_64                               23/24   Installing : unzip-6.0-4.10.amzn1.x86_64                                24/24   Verifying  : libjpeg-turbo-1.2.90-5.14.amzn1.x86_64                      1/24   Verifying  : groff-1.22.2-8.11.amzn1.x86_64                              2/24   Verifying  : unzip-6.0-4.10.amzn1.x86_64                                 3/24   Verifying  : python27-pyasn1-0.1.7-2.9.amzn1.noarch                      4/24   Verifying  : groff-base-1.22.2-8.11.amzn1.x86_64                         5/24   Verifying  : aws-cli-1.14.9-1.48.amzn1.noarch                            6/24   Verifying  : python27-six-1.8.0-1.23.amzn1.noarch                        7/24   Verifying  : python27-dateutil-2.1-1.3.amzn1.noarch                      8/24   Verifying  : python27-docutils-0.11-1.15.amzn1.noarch                    9/24   Verifying  : python27-PyYAML-3.10-3.10.amzn1.x86_64                     10/24   Verifying  : python27-botocore-1.8.13-1.66.amzn1.noarch                 11/24   Verifying  : python27-futures-3.0.3-1.3.amzn1.noarch                    12/24   Verifying  : python27-ply-3.4-3.12.amzn1.noarch                         13/24   Verifying  : python27-jmespath-0.9.2-1.12.amzn1.noarch                  14/24   Verifying  : mailcap-2.1.31-2.7.amzn1.noarch                            15/24   Verifying  : python27-backports-ssl_match_hostname-3.4.0.2-1.12.amzn1   16/24   Verifying  : libyaml-0.1.6-6.7.amzn1.x86_64                             17/24   Verifying  : python27-rsa-3.4.1-1.8.amzn1.noarch                        18/24   Verifying  : freetype-2.3.11-15.14.amzn1.x86_64                         19/24   Verifying  : python27-colorama-0.2.5-1.7.amzn1.noarch                   20/24   Verifying  : python27-setuptools-36.2.7-1.33.amzn1.noarch               21/24   Verifying  : which-2.19-6.10.amzn1.x86_64                               22/24   Verifying  : python27-imaging-1.1.6-19.9.amzn1.x86_64                   23/24   Verifying  : python27-backports-1.0-3.14.amzn1.x86_64                   24/24 Installed:   aws-cli.noarch 0:1.14.9-1.48.amzn1        unzip.x86_64 0:6.0-4.10.amzn1   which.x86_64 0:2.19-6.10.amzn1   Dependency Installed:   freetype.x86_64 0:2.3.11-15.14.amzn1   groff.x86_64 0:1.22.2-8.11.amzn1   groff-base.x86_64 0:1.22.2-8.11.amzn1   libjpeg-turbo.x86_64 0:1.2.90-5.14.amzn1   libyaml.x86_64 0:0.1.6-6.7.amzn1   mailcap.noarch 0:2.1.31-2.7.amzn1   python27-PyYAML.x86_64 0:3.10-3.10.amzn1   python27-backports.x86_64 0:1.0-3.14.amzn1   python27-backports-ssl_match_hostname.noarch 0:3.4.0.2-1.12.amzn1   python27-botocore.noarch 0:1.8.13-1.66.amzn1   python27-colorama.noarch 0:0.2.5-1.7.amzn1   python27-dateutil.noarch 0:2.1-1.3.amzn1   python27-docutils.noarch 0:0.11-1.15.amzn1   python27-futures.noarch 0:3.0.3-1.3.amzn1   python27-imaging.x86_64 0:1.1.6-19.9.amzn1   python27-jmespath.noarch 0:0.9.2-1.12.amzn1   python27-ply.noarch 0:3.4-3.12.amzn1   python27-pyasn1.noarch 0:0.1.7-2.9.amzn1   python27-rsa.noarch 0:3.4.1-1.8.amzn1   python27-setuptools.noarch 0:36.2.7-1.33.amzn1   python27-six.noarch 0:1.8.0-1.23.amzn1   Complete! Removing intermediate container 1f5293a2294d  ---> 5502efa481ce Step 3/6 : ADD fetch_and_run.sh /usr/local/bin/fetch_and_run.sh  ---> 1b69173e586f Step 4/6 : WORKDIR /tmp Removing intermediate container a69678c65ee7  ---> 8a560dd25401 Step 5/6 : USER nobody  ---> Running in e063ac6e6fdb Removing intermediate container e063ac6e6fdb  ---> e5872fd44234 Step 6/6 : ENTRYPOINT ["/usr/local/bin/fetch_and_run.sh"]  ---> Running in e25af9aa5fdc Removing intermediate container e25af9aa5fdc  ---> dfca872de0be Successfully built dfca872de0be Successfully tagged awsbatch-fetch_and_run:latest docker images 명령으로 새로운 로컬 repository를 확인할 수 있습니다.shell : docker images [ec2-user@AWS_BRANDI_STG fetch-and-run]$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE fetch_and_run latest dfca872de0be 2 minutes ago 253MB amazonlinux              latest              81bb3e78db3d        2 weeks ago         165MB STEP3. ECR에서 repository 생성아래는 ECR 초기 화면입니다.fetch_and_run이란 이름으로 Repository 생성합니다. 3. Repository 생성이 완료되었습니다.STEP4. ECR로 빌드된 이미지를 pushECR에 docker login후 빌드된 Docker 이미지에 태그합니다. shell : aws ecr get-login --no-include-email --region ap-northeast-2 빌드된 docker 이미지에 태그하세요.shell : docker tag fetch_and_run:latest 000000000000.dkr.ecr.ap-northeast-2.amazonaws.com/fetch_and_run:latest 태그된 docker 이미지를 ECR에 push합니다.shell: docker push 000000000000.dkr.ecr.ap-northeast-2.amazonaws.com/fetch_and_rrun:latest 아래는 ECR fetch_and_run Repository에 푸쉬된 Docker 이미지입니다.STEP5. 간단한 샘플 스크립트(myjob.sh)를 S3에 업로드아래는 간단한 myjob.sh 스크립트입니다.#!/bin/bash date echo "Args: $@" env echo "This is my simple test job!." echo "jobId: $AWS_BATCH_JOB_ID" sleep $1 date echo "bye bye!!" 위의 myjob.sh를 S3에 업로드합니다.shell : aws s3 cp myjob.sh s3:///myjob.sh STEP6. IAM에 S3를 접속할 수 있는 ECS Task role 등록Role 등록 화면에서 Elastic Container Service 선택 후, Elastic Container Service Task를 선택합니다.AmazonS3ReadOnlyAccess Policy를 선택합니다.아래 이미지는 Role에 등록 하기 전 리뷰 화면입니다.Role에 AmazonS3ReadOnlyAccess가 등록된 것을 확인합니다.STEP7. Compute environments 생성AWS Batch 콘솔에서 Compute environments를 선택하고, Create environment 선택합니다.Compute environment type은 Managed와 Unmanaged 두 가지를 선택할 수 있습니다. Managed는 AWS에서 요구사항에 맞게 자원을 관리해주는 것이고, Unmanaged는 직접 자원을 관리해야 합니다. 여기서는 Managed를 선택하겠습니다.Compute environment name을 입력합니다.Service Role을 선택합니다. 기존 Role을 사용하거나 새로운 Role을 생성할 수 있습니다. 새 Role을 생성하면 필수 역할 (AWSBatchServiceRole)이 생성됩니다.Instnace Role을 선택합니다. 기존 Role을 사용하거나 새로운 Role을 생성할 수 있습니다. 새 Role을 생성하면 필수 역할(ecsInstanceRole)이 생성됩니다.EC2 key pair에서 기존 EC2 key pair를 선택합니다. 이 key pair를 사용하여 SSH로 인스턴스에 접속할 수 있지만 이번 글의 예제에서는 선택하지 않겠습니다.Configure your compute resources Provisioning Model은 On-Demand와 Spot이 있습니다. 차이점은 Amazon EC2 스팟 인스턴스를 참고해주세요. 여기서는 On-Demand를 선택합니다.Allowed instance types에서는 시작 인스턴스 유형을 선택합니다. optimal을 선택하면 Job queue의 요구에 맞는 인스턴스 유형을 (최신 C, M, R 인스턴스 패밀리 중) 자동으로 선택합니다. 여기서는 optimal을 선택하겠습니다.Minimum vCPUs는 Job queue 요구와 상관없이 Compute environments에 유지할 vCPU 최소 개수입니다. 0을 입력해주세요.Desired vCPUs는 Compute environment에서 시작할 EC2 vCPU 개수입니다. Job queue 요구가 증가하면 필요한 vCPU를 Maximum vCPUs까지 늘리고 요구가 감소하면 vCPU 수를 Minimum vCPUs까지 줄이고 인스턴스를 제거합니다. 0을 입력해주세요.Maximum vCPUs는 Job queue 요구와 상관없이 Compute environments에서 확장할 수 있는 EC2 vCPU 최대 개수입니다. 여기서는 256을 입력합니다.Enable user-specified Ami ID는 사용자 지정 AMI를 사용하는 옵션입니다. 여기서는 사용하지 않겠습니다.Networking VPC Id 인스턴스를 시작할 VPC를 선택합니다.Subnet을 선택합니다.Security groups를 선택합니다.그리고 EC2 tags를 지정하여 생성된 인스턴스가 이름을 가질 수 있게 합니다. Key : Name, Value : AWS Batch InstanceCreate을 클릭해 Compute environment를 생성합니다.아래 이미지는 생성된 Compute environment입니다.STEP8. Job queues 생성AWS Batch 콘솔에서 Job queues - Create queue를 선택합니다.Queue name을 입력합니다.Priority는 Job queue의 우선순위를 입력합니다. 우선순위가 1인 작업은 우선순위가 5인 작업보다 먼저 일정이 예약됩니다. 여기서는 5를 입력하겠습니다.Enable Job queue가 체크되어 있어야 job을 등록할 수 있습니다.Select a compute environment에서 Job queue와 연결될 Compute environment을 선택합니다. 최대 3개의 Compute environment를 선택할 수 있습니다.생성된 Job queue, Status가 VALID면 사용 가능합니다.STEP9. ECR을 이용하여 Job definition 생성AWS Batch 콘솔에서 Job definitions - Create를 선택합니다.Job definition name을 입력하고 이전 작업에서 만들 IAM Role을 선택하세요, 그리고 ECR Repository URI를 입력합니다. 000000000000.dkr.ecr.ap-northeast-2.amazonaws.com/fetch_and_runCommand 필드는 비워둡시다.vCPUs는 컨테이너를 위해 예약할 vCPU의 수, Memory(Mib)는 컨테이너에 제공할 메모리의 제한, Job attempts는 작업이 실패할 경우 다시 시도하는 최대 횟수, Execution timeout은 실행 제한 시간, Ulimits는 컨테이너에 사용할 사용자 제한 값입니다. 여기서는 vCPUs는 1, Memory(MiB)는 512, Job Attempts는 1로 설정, Execution timeout은 기본값인 100 그리고 Limits는 설정하지 않습니다.vCPUs: 컨테이너를 위해 예약할 vCPU의 개수Memory(Mib): 컨테이너에 제공할 메모리의 제한Jop attempts: 작업이 실패할 경우 다시 시도하는 최대 횟수Execution timeout: 실행 제한 시간Ulimits: 컨테이너에 사용할 사용자 제한 값User는 기본값인 nobody로 선택 후, Create job definition을 선택합니다.Job definitions에 Job definition이 생성된 것을 확인할 수 있습니다.STEP10. Submit job을 통해 S3에 저장된 작업 스크립트(myjob.sh)를 실행하기AWS Batch 콘솔에서 Jobs를 선택합니다. Job을 실행할 Queue를 선택하고 Submit job을 선택합니다.Job run-time1)Job name을 입력합니다.2)Job definition을 선택합니다.3)실행될 Job queue를 선택합니다.Environment Job Type을 선택하는 부분에서는 Single을 선택합니다. Array 작업에 대한 자세한 내용은 어레이 작업 페이지를 참고해주세요.Job depends on은 선택하지 않습니다.자세한 내용은 작업 종속성 페이지를 참고해주세요.Environment Command에서 컨테이너에 전달할 명령을 입력합니다. 여기서는 [“myjob.sh”, “30”] 를 입력해주세요. vCPUs, Memory, Job attempts와 Execution timeout은 job definition에 설정된 값을 가져옵니다. 이 Job에 대한 설정도 가능합니다.Parameters를 통해 job을 제출할 때 기본 작업 정의 파라미터를 재정의 할 수 있습니다. Parameters에 대한 자세한 내용은 작업 정의 파라미터 페이지를 참고해주세요.Environment variables는 job의 컨테이너에 환경 변수를 지정할 수 있습니다. 여기서 주의할 점은 Key를 AWS_BATCH로 시작하면 안 된다는 것입니다. AWS Batch에 예약된 변수입니다.Key=BATCH_FILE_TYPE, Value=script Key=BATCH_FILE_S3_URL, Value=s3:///myjob.shSubmit job을 선택합니다.Job이 Submitted 된 화면입니다.Dashboard를 보시면 Runnable 상태로 대기 중인 것을 확인할 수 있습니다.STEP11. 결과 확인CloudWatch > Log Groups > /aws/batch/job에서 실행 로그를 확인할 수 있습니다.Conclusion간단한 튜토리얼로 AWS Batch를 설정하고 실행하는 방법을 알아봤습니다.(참 쉽죠?) 다음 글에서는 AWS Batch의 Array 또는 Job depends on등의 확장된 기능들을 살펴보겠습니다. 참고1) AWS Batch – 쉽고 효율적인 배치 컴퓨팅 기능 – AWS2) AWS Batch 시작하기 - AWS Batch3) Amazon ECR의 도커 기본 사항 - Amazon ECR글윤석호 이사 | 브랜디 [email protected]브랜디, 오직 예쁜 옷만#브랜디 #개발문화 #개발팀 #업무환경 #인사이트 #경험공유
조회수 1302

[우리는 비투링커 #4] '빵빠레' 하나면 행복한 그녀, 박예지 님 ♥

안녕하세요, 비투링크의 소식을 전하는 미나 입니다! 벌써 한달이 지나, 다시 돌아 온 [우리는 비투링커] 시간인데요.3월의 비투링커로 선정된 그녀는 누구일까요?'빵빠레' 라면... 요거?*~*~짜잔~*~*자.. 먼저 추천영상을 함께 보시죠!이번 영상의 주제는 "엽기적인 그녀" 입니다 (ㅋㅋㅋ)보고있으면 참 밝은 그녀는 누구일지!▼▼영상 클릭 클릭▼▼3월의 비투링커 추천영상 (영상 고퀄주의 ㅋㅋㅋㅋ)그 주인공은... "엽기적인(?) No No~ 보고있으면 참 밝은 그녀" 박예지님 입니다!(짝짝짝짝!!!!!)3월의 비투링커 박예지님 :)특별히 빵빠레를 먹으면서 인터뷰 하고 싶었지만....빵빠레가 회사근처에 안팔더라구요 (또르르)그래서 그냥 빈손으로 예지님을 만났습니다.그래도 활짝 웃고 있던 그녀...................^^안녕하세요, 저는 비투링크 Brand Operation Division 내 구매팀에서제품구매, 발주 및 운영을 담당하고 있는 박예지 입니다 ^_^정말 0.1%도 예상치 못했어요. 팀원들이랑 꽤 친하다고 생각했는데, 정말 아무도 말을 안해주더라구요 ㅋㅋㅋ 그래서 제가 타운홀미팅날 연차를 써서 직접 영상을 못봐서 아쉬워요 ㅠㅠ그래도 이후에 영상을 봤는데, 진짜 행복했어요 ^_^ 보면서 같은 팀 제용님의 흑역사가 될 거 같다는 생각이 살짝 들었지만요...........:) 사실은 전 워낙 스트레스를 안받는 성격이기도 해요!또, 받게되면 내부에서 받기보다는, 외부 거래처와 커뮤니케이션을 하며 받는 스트레스가 대부분이에요. 그래서 팀원들이랑 같이 얘기하고, 간식을 사먹는다던지, 달달한 커피를 마시러 간다던지, 바깥공기를 쐬러 간다던지 ㅋㅋ 많은 것들을 팀원들과 함께 해요 :)슬픈 건, 요즘 회사근처에 빵빠레가 안팔아요..................... (슬퍼요 ㅠ_ㅠ)옛날엔 2+1 행사하고 그랬는데... 대체품을 찾고 있는데, 빵빠레를 대신 할 수 없을거같아요 ㅋㅋㅋ작년 송년회 때 같이 찍은 팀사진!주말엔 주로 제가 키우는 강아지 (단추) 랑 시간을 보내요 ^_^눈이 단추구멍 같아서 ㅋㅋㅋ 이름이 단추에요 (크큭)너무 애교쟁이 ㅠㅠ그리고, 제가 요즘 찾은 저만의 비밀스러운....... 문화생활이 있는데요.저 폴댄스 배웁니다!!!! 지금 거의 6개월 째 하고 있는데요. 정말 재밌어요 ^_^사진은...공개할 슈 없숴요~ (부끄러움)대박! 폴댄스라니 :) 멋져멋져... 저는 사실 몰래 예지님이 폴댄스하시는 사진 봤는데장난아니네여 섹시해 ㅠㅠ 저두 하고싶어요 ㅋㅋㅋㅋㅋㅋ제 컵이름은 "구갈동 빨간거" 입니다 ㅋㅋㅋ제 별명 너무 대충 지은거 같아요 ㅋㅋㅋ 불만이에요 !!이유는 제가 맨날 입술을 빨갛게 바르고 다녀서 ..........ㅋㅋㅋㅋㅋㅋㅋㅋㅋ근데 또 바꿔달라고 하기 무서워요 ㅋㅋ이상한 별명할까봐여... 빨간걸로 있을게요 그냥(좌) 한스킨 Blemish Cover (우) 23 Years old Sibiton cream [출처: 네이버 블로그]저는 한스킨 블레미쉬 커버 (Blemish Cover) 과 23 Years Old 시비통 크림 (Sibiton Cream) 을 추천합니다 :) 첫 번째 제품은, 컨실러 제품인데요. 커버력이 진짜 좋으면서도 촉촉한 게 장점! 휴대하기도 편하고, 가끔을 얇게 펴바르면 BB크림처럼도 사용할 수 있어요!두번째 제품은 크림인테, 이름이 약간 욕같져? ㅋㅋ 피부에 보호막을 설치해줘서 수분감도 오래 지속되고, 붉은 홍조피부 진정효과도 있어서 데일리로 사용하기 좋은 비타민 크림이에요!(친구한테 추천해줬는데, 친구가 지금까지도 계속 사용하고 있어요 ㅋㅋ)올해를 시작하면서 많은 계획을 세웠는데요!그 중에 꼭 이루고 싶은 건, "유럽여행" 을 가는 거에요 ^_^원래 1년에 한번 이상은 꼭 해외여행을 가는데요, 가장 멀리 갔던 게 동남아 였어요!올해가 제가 앞으로 살 날 중에 가장 젊고 예쁠 때니까꼭 가보도록 하겠습니다 :)손잡아주실 분 찾습니다 ^^....인터뷰 하는내내 예지님 때문에 저도 계속 웃었던 거 같아요 ㅎㅎㅎ앞으로도 계속 미소 잃지않는 밝은 예지님으로 ^_^(담엔 빵빠레 같이 먹어효)#비투링크 #팀원 #팀원소개 #팀원인터뷰 #인터뷰 #팀원자랑 #기업문화
조회수 3357

어리석은 일잘러의 슬픈 착각 13가지

간만에 일 얘기로 좀 돌아왔어요. 오늘은 일잘러 얘기랍니다. 브런치나 구글, 일분, 카카오채널, 블로그, 팟캐스트, 유튜브...등등 모든 채널에 '일' 에 대한 얘기가 가득해요. 대부분 두 가지 아젠다가 있더군요. 1. 일을 잘하는 방법2. 일을 못하는 이유이겁니다. 모두의 행복한 업무생활을 위한 좋은 콘텐츠들이지만, 이런 테마가 넘쳐나고 이래저래 공유되면서 모든 사람들이 일을 잘해야 하고, 일을 못하는 건 일종의 죄...? 처럼 여겨지는 부분도 생기는 듯 해요. 일정부분 동의해요. 일을 못하는 건 어떤 측면에서 민폐가 될 수 있겠죠. 개냉정한 말이지만, 결국 당신의 일못함은 다른 누군가의 피해와 희생을 요구하거든요. 그러니 업무적으로 여러가지 열폭 컨텐츠가 등장하는 것이 이해는 갑니다. 하지만 좀 불편한 부분이 있었어요. 소위 자칭 일잘러들의 미묘한 깔아봄이 있더라구요? 마치 일 잘하는 사람이 조금 더 나은 우성종자같은 행세를 하고 다닌다는 거죠. 그리고 자꾸 일손이 느리거나 실수가 잦은 누군가를 가르치려 들거나(기분나쁘게) 또는 깝깝하다는 듯한 제스쳐를 취하는 모습을 자주 보곤 했어요. 문득 그런 생각이 들죠. 뭐지 저 자의식은?... 어디서 일잘함 인증이라도 받아온 건가..싶은.물론 그럴 수 있죠. 진짜 일처리가 AI마냥 정확한 종족들이 있어요. 그럼 그냥 본인에게 좋은 일이죠. 빨리 끝내고 빨리 퇴근하고 쉴 수 있으니 부모님께 감사하면 될 일입니다. 그래요 이분들은 인정합니다.하지만 종종.. 아무리 봐도 일을 잘하지 않는데... 본인이 일을 잘한다고 착각하는 분들이 있더라구요.  오늘은 자칭 일잘러들의 슬픈 착각을 좀 까보려고 합니다. 1. 멋진 단어 VS 쉬운 단어일잘러는 중학생들도 블록체인을 이해할 수 있게 설명하는 분들입니다. 자칭 전문가라며 말도 안되는 영어와 약어, 전문용어를 마구 섞어서 말씀하시는 분들이 있는데 대충 느낌은 알겠습니다. 의사들의 처방전같은 전문성을 어필하고 싶었던 모양입니다. 하지만 그것은 파스타 속의 브로콜리마냥 굉장히 거슬리는 거에요. 빼고 먹고싶은데 자꾸 달팽이관에 걸려서 불편하달까요. (전 브로콜리를 싫어해요.)2. 말이 많은 것 VS 말을 잘하는 것LA들어간다 귀벌려본인의 주장을 설명하기 위해 수백마디의 근거와 예시가 필요하다면 이미 그 주장은 힘이 없는 거예요. 가끔 목소리 크고 또박또박한 발성으로 몇 시간 내내 트렌드와 동향, 방대한 자료와 근거를 들어 주절주절 멋진 일대일 강의를 하시는 분들이 있는데... 그건 '말을 잘 하는 것 처럼' 보여요. 하지만 귀에 남는 건 아무것도 없다구요. 계졀밥상에서 2시간 내내 계속 다른 메뉴먹는 느낌이야. 배는 부른데 뭘 먹었는지 모르겠어. 짧고 간결하지만 쏙쏙 이해되는 어휘로 명확한 근거 하나로 부연하는 게 능력이예욤.3. 냉철한 것 VS 싸가지없는 거일을 할 때 냉정한 것과 싸가지가 없는 건 다릅니다. 일을 하라고 했지 인격을 건들라고는 안했거든요. 가끔 '결과를 잘 내기 위해서' 냉정하고 사정 봐주지 않는 오더를 내리시는 분들이 있는데, 진짜 일을 잘 하시는 분들은 사람의 소중함을 먼저 캐치하시지 않을까요? 도깨비방망이마냥 사람을 갈아넣으면 어떤 일이든 할 수 있습니다. '다음'이 없을 뿐.4. 빨리 하는 것 VS 대충하는 것이렇게 빨리해도 잘해야지.빨리하라고 했지 대충하라곤 안했습니다. 쟈긴 막 일잘한다고 후다다닥 끝내놓고 커피 한 잔 마신다고 어디 나가있고 그러는데..막상 인수인계 받아서 작업해보면...빈 구석이 너무 많아서 다시 피드백 정리하거나 요청하고, 아님 내가 그냥 만드느라 더 느려져요. 성격급하고 빠르게 일처리 해놓고 딩가딩가하는 건 일을 잘하는 게 아닌 것 같아요. 빠르고 정확하게 해야죠.5. 완벽주의 VS 그냥 일손이 느린 타입'어우 저는 완벽주의 라서요!.. 꼼꼼하게 하나하나 보는 타입이예요.'꼼꼼하게 보고 완벽하게 하는 거 다 좋은데, 마감시간은 맞췄으면 합니다. 그냥 일손이 느린 거에 대한 묘한 변명같아요. 6. 프로다움 VS 그냥 드러운 성격거들먹거리는 말투로 '나랑 일하기 힘들 거야.' 이라고 자기어필 하시는 사수가 있더라구요. 뭐 어쩌라는 걸까요? 싸우자는 걸까요..오지말라는 걸까요. 그게 소위 프로다움이라고 여기시는 분들이 종종 있더라구요. 밑에 부사수를 조져서 일을 '가르쳐줄거다' 그러니 너가 내 속도에 따라와라.. 하는 건데. 여긴 군대가 아니에요. 그건 프로다운 게 아니라, 사람을 다루지 못하는 미숙함이고 그냥 성격이 더러운 게 아닐까 싶습니다.7. 빠른 의사 결정 VS 독선과 고집의사결정이란 건 일단 듣고 각 의견의 장단점을 구분해서 취사선택 또는 합의점을 도출하는 거에요. 팀원들이 20가지 아이디어를 내고 10가지 피드백을 냈는데 결국 피드백은 쌩까고 본인이 낸 아이디어를 선택했다면 그건 의사결정일까요? 종종 이런 독단을 '난 쿨하게 의사결정하는 편이야! 길게 끌지 않아.' 라고 생각하는 분들이 있는데 그거 아닙니다. 그냥 고집쟁이세요.8. 자기반성 VS 정신승리페북에다가 자꾸 자기반성 글 쓰시는 분들 있어요. 회고 비슷하게. 알겠는데, 자기반성은 개선점이 행동으로 드러나야 의미가 있는 겁니다. 페북에다가 의지만 불태우는 건 그냥 정신승리에요. 뭔가 문제가 있었고 갈등이 있었다면 재빨리 해결하고 당사자에게 사과를 구하고 행동으로 보여주면 될 일입니다. 9. 일잘러 VS 뒷담쟁이일을 잘 한다는 건 벼슬이 아닙니다. 누군가를 깔 일도 아니죠. 항상 내가 일 잘하는 것처럼 느껴질 때는 그런 생각이 든단 것 자체가 '지금 내가 좆밥이구나' 라는 걸 잘 기억해야 합니다.10. 이론쟁이 VS 재수탱이일을 어디 교과서로 배웠는지 자꾸 연습문제 뒷장에 '생각해봅시다.' 같은 질문들만 던지고는 팔짱을 끼는 분들이 있어요. 이런 사람들이 잘 팔아먹는 단어가 '기획'과 '전략' 인데.... 기획은 책상앞에서 펜대굴리면서 하는 게 아니더라구요. 이론만으로 하는 것도 아니고. 아이디어만(그것도 시덥잖은) 내놓고 자꾸 데카르트같은 딴지만 거는 분이 있다면 조용히 귓속에 집에 가라고 속삭여주세요. 지금 발로 뛰면서 현장서베이 다니고 레퍼런스 찾기도 바쁘니까.11. 인사이트 VS 헛소리인사이트..라는 단어가 21세기 멋진 단어 BEST5에 등극한 모양인데 인사이트라는 건 심도를 꿰뚫는 깊이와 다양한 근거를 바탕으로 내는 가설이자 관점입니다. 페북에서 공유해온 글3,4개 읽고 떠들고 다니는 '내 생각' 정도가 아니라고 생각해요. 어디서 복제해온 정보들을 내 것이라고 착각하면 안돼요. 12. 유도리 VS 가라일을 유연하고 상황에 맞춰 해결하는 능력은 매우 중요합니다. 우린 이걸 유연성 내지는 유도리라고 하죠. 근데 이게 모든 일을 그냥 대충 그때 그때 임시방편으로 처리하란 얘기가 아니에요. 가끔 말예요. 직급이 올라가고 권한이 생길 수록 이 유도리를 시도때도 없이 써먹는 분들이 있더라구요. '그냥 대충 해, 내가 잘 말할께!''아 그분 내가 아는 분이야, 그냥 그렇게 한다고 해''이번거 그냥 사, 내가 이사님한테 말할께. 술 사드리면 풀려.'직원입장에선 개쿨하고 능력쩌는 상사같아 보일 수도 있겠지만..결국 이런 식의 일처리는 어느 지점에선 터지게 되어있거든요. 가라와 유도리는 좀 다릅니다. 정상적인 절차 내에서도 효율적인 결론을 만들 수 있어야 레알 일잘러죠. 13. 용기있는 1인 VS 딴지쟁이모두가 YES라고 말할 때 NO라고 말하는 소신있는 일잘러분들이 있어요. 좋아요. 그런 자세. 모두에게 좋은 결과를 위해 전투적으로 리스트를 도출하고 어필하는 거 좋습니다. 뭐 한 편으론 '불평만 말하지 말고, 해결책을 가져와라' 라는 말도 있던데, 솔직히 해결책 안가져와도 됩니다. 리스크를 발견한 것만도 대단한 거에요. 문제는 그 리스크가 진짜 '유의미'한 리스크인가 하는거죠. 괜히 색이 맘에 안들고, 디자인이 어떻고, 뭔가 그냥 느낌적으로 별로인 것 같고, 사람들이 그냥 안좋아할 것 같고, 자기 친구들3명한테 물어봤는데 이거 아니라더라....이런식의 피드백은 졸라 그냥 딴지일 뿐입니다. 남의 말 잘라먹고 자기 주장 좋아하고 불평을 똑부러진 말투로 늘어놓는 것 뿐이죠.  일을 잘 하는 건 기획안을 몇 분안에 만들 수 있느냐..로 평가되는 게 아니라고 생각해요. 게다가 또박또박과 똑부러짐, 전문적이고, 말빠르고, 목소리크고, 성격급하고, 까칠하고, 고집있는 건 일잘러와는 사실 별 상관이 없어요. 그건 그냥 성격이나 성향문제일 뿐이죠. 회사와 동료 앞에는 모두 co- 접두어가 들어가잖아요. 일의 본질은 '함께' 하는 겁니다. 지가 못하는 게 있으면 도움을 빠르게 요청하고, 내가 잘 하는 게 있으면 부족한 분과 콜라보해서 빨리 끝내고. 일을 '돌아가게' 만드는 사람이 진짜 일잘러가 아닐까욤..
조회수 76113

잘 쓴 자기소개서의 다섯 가지 특징

채용 서비스를 하고 있는 스타트업의 마케터이다 보니 하루에도 수십 개의 합격 자기소개서를 보게 됩니다. 물론 이 자기소개서들이 100% 합격 자소서가 맞는지, 그리고 그 이후에 어떻게 되었는지에 대해 알 순 없습니다만, 어찌 됐든 '합격 자소서'라고 올라온 글들을 수 없이 많이 보고 있습니다.그렇게 수많은 합격 자소서를 보면서 느꼈던 '잘 쓴 자기소개서의 특징'을 다섯 가지 정리해보도록 하겠습니다. 앞서 이야기해둘 것은 저는 어느 대기업의 인사 담당자도 아니고, 인사팀의 입장에서 자기소개서를 본 것도 아니라는 점입니다. 제 3자의 입장에서, 그리고 글 쓰는 것과 읽는 것을 좋아하는 사람의 입장으로서 느꼈던 것들입니다.첫째, 글빨보다는 '컨텐츠' 많은 합격 자기소개서를 보면서 가장 놀랍고 크게 와 닿았던 것은 자기소개서를 쓸 때 생각보다 글을 화려하게 잘 쓸 필요가 없다는 것이었습니다. 초등학교 때로 돌아가, 집에서 미술 숙제를 해야 하는데 엄마가 조금이라도 도와주면 티가 팍 나는 것처럼, 너-무 잘 쓴 자기소개서는 오히려 더 튀는 느낌이 들었습니다. (이 '너-무 잘 쓴 자기소개서'라는 것은 평균 이상의 글쓰기 실력이라기보다는, 실무나 회사 생활을 좀 해본 사람들의 향기가 좀 나는 자기소개서를 말합니다.) 오히려 덤덤하게 자신이 가진 컨텐츠를 풀어내는 것이 조금 서툴어 보이더라도 읽는 사람을 편안하게 만들어 주었습니다. 억지로 미사여구를 붙인다거나 한자성어나 전문용어를 가져다 쓰는 것보다는 지원 회사/직무에 맞는 관련된 경험을 잘 인용하여 쓰는 것이 합격에는 중요한 요소로 보입니다. 전공 수업에서의 팀플을 쓰건, 아르바이트했던 경험을 쓰건 대단한 실무 경험을 쓰지 않아도 괜찮았습니다. 입사에 대한 열의를 보여줄 수 있는 컨텐츠인지, 그 직무를 지원하고 싶어서 그동안 해왔던 노력들인지가 중요합니다. 하지만 생각보다 많은 지원자들이 자신이 가진 컨텐츠, 본질, 핵심보다는 보여지는 겉모습, 표현에 신경 쓰는 것 같습니다. 자기소개서라는 것은 나를 어필하고 함께 일하고 싶은 인재임을 표현하는 수단인 건데, 그렇다면 진짜 중요한 것이 무엇인지 생각해 볼 필요가 있겠습니다. 둘째, 컨텐츠에는 '진정성' 앞의 이야기와 이어질 수 있겠지만, 특정 기업과 직무에 지원하는 '자기소개서'를 씀에 있어서 가장 중요한 것은 '경험'입니다. 여러 자기소개서 문항들이 구체적인 사례를 디테일하게 물어보는 이유는 '진정성'에 있습니다. "얼마나 우리 회사에 오고 싶었니? 얼마나 지원 직무를 준비해왔니?" 가, 그 경험에 담기기 마련입니다. 즉, 꾸준하고 일관되게 그 회사, 직무를 지원하기 위해 준비해왔던 경험들에는 '진정성'이 느껴집니다.인상 깊은 합격 자기소개서 사례를 들어 이야기하자면 이렇습니다. 교육 관련 전공을 한 사람이 인사팀에 지원을 한 케이스였습니다. 그 사람이 우연히 조직/인사와 관련된 경영학과 수업을 듣게 되었는데 그때 학생을 가르치는 것만큼이나 성인들의 잠재력을 키워주는 일도 재밌다는 것을 느꼈고, 그래서 MBTI 강사 과정을 수료, 이후에 MBTI를 활용한 기업 인사 프로그램에도 참여하게 되었다고 합니다. 그때 모 기업의 인사 담당자를 만나게 되었고, 그와 이야기를 나누면서 모 기업의 철학, 인사팀이 하는 어떠어떠한 일이 자신이 꿈꿔왔던 커리어와 잘 맞는다고 생각이 들어 지원하게 되었다, 는 골자였습니다. 어떻게 보면 "경영학 전공자도 아니고 교육 전공한 사람이 왜 인사팀을 지원했어요?"라고 생각이 들 수 있는 조건이지만, 어떤 계기로 '인사 직무'에 관심을 가지게 되었는지, 인사 직무를 하기 위해서 어떤 노력을 해왔는지가 잘 담겨있는 내용이었습니다. 자신의 경험들을 잘 이어서 직무와 연결시켜보면 이렇게 진정성이 느껴지는 자기소개서를 작성할 수도 있는 것입니다.  셋째, 진정성에는 '철학' 그런데 이 '진정성'에서 또 중요한 것이 단순히 '경험 나열'만 해서는 안 된다는 것입니다. 그 회사/직무에 지원하기 위해서 어떤 준비를 해왔는지 경험들을 이야기했지만, 그 과정에서 어떤 교훈을 얻었는지 '느끼는 바'가 없으면 껍데기만 있을 뿐입니다. 위의 인사팀 지원자 사례로 계속 이야기하자면, 학생들 가르치는 것뿐만 아니라 성인, 조직을 교육하는 것의 '어떤 점'이 재미있었는지,에 대해서 이야기했기 때문에 신뢰감 있게 들렸습니다. 예컨대 "어느 정도 인격과 자아가 형성되어 정말 다양한 성향을 가진 성인들이 모여있는 회사라는 조직에서 MBTI로 구성원들의 성향을 파악하고 소통을 도와주는 것이 재미가 있었고, 이 과정에서 서로를 이해하고 더 높은 목표를 이루기 위해서 나아가는 모습을 볼 때 보람찼다"와 같은 포인트입니다. 요약하자면 회사/직무에 지원하기 위해서 어떤 경험들을 쌓아왔는지 그 경험들을 하면서 무엇을 느꼈고, 어떤 점에서 그 회사/직무에 지원을 해야겠다는 확신을 가지게 되었는지 철학이 담기면 80% 이상은 쓴 것이라 볼 수 있습니다. 그리고 이러한 철학은 다른 지원자들과 나의 자기소개서를 차별화시켜주는 포인트가 되기도 합니다. 지원자 입장에서 이렇게까지 생각하는 것이 조금 귀찮을 수도 있지만, 그래도 자기소개서 작성 전에 꼭 생각해보면 좋습니다.  넷째, 하고 싶은 말을 하기보다는 묻는 말에 '충실히' 대답하기많은 합격 자기소개서를 읽다 보니 공통점이 있었습니다. 바로 질문의 의도에 맞게 핵심 위주로 대답했다는 것입니다. 특히 요새는 지원자들에게 혼란을 덜 주기 위하여 자기소개서 문항도 예전보다 더 자세해지고 있습니다. 자기소개서를 쓰려고 하는데 문항이 길다면 어려워하지 말고 오히려 감사하게 생각해도 좋습니다. 제시된 질문을 '잘' 파악하여 대답만 잘 해도 상당 분량이 채워질 수 있기 때문입니다. 예를 들면 자기소개서 문항이 자세하기로 정평이 난 SK 그룹의 경우, 이러한 문항이 있습니다. 자신에게 요구된 것보다 더 높은 목표를 스스로 세워 시도했던 경험 중 가장 기억에 남는 것은 무엇입니까? 목표 달성 과정에서 아쉬웠던 점이나 그때 느꼈던 자신의 한계는 무엇이고, 이를 극복하기 위해 했던 행동과 생각, 결과에 대해 최대한 구체적으로 작성해 주십시오.'도전이나 한계 극복 경험'을 물어보는 문항은 다른 회사에서도 많이 제시됩니다. 하지만 이렇게 자세하게 물어봤을 경우에는 질문을 쪼개서 질문 안의 내용들에 충실하게 답변하도록 내용을 구성하면 됩니다. 위 문항의 경우, (1) 도전 경험이 무엇인지 (2) 그 과정이 어땠는지 (3) 특별히 아쉬웠던 점은 무엇인지 (3) 그때 느낀 나의 한계와 (4) 극복하기 위해서 어떤 행동을 했는지 (5) 왜 그런 생각을 했는지 (6) 그에 따른 결과는 어땠는지를 쓰면 됩니다. 합격 자기소개서들은 이렇게 물어보는 질문들에 대한 대답을 충실히 하는 경향이 있습니다. 여기에 자신이 추가하고 싶거나 강조하고 싶은 부분을 더했으면 더했지 이것들을 대충 언급하지 않았습니다. 일단 긴 문항이 나온다면 그것을 쪼갠 뒤, 핵심 내용만 채워도 글자 수를 채우기가 훨씬 쉬워질 것입니다. 마지막, 화룡점정은 역시 '글빨' 그렇다면 정말 '글빨'이 안 중요한가? 사실 그렇지 않습니다. 하지만 글빨도 앞서 말했던 것처럼 내용이 좋다면 어느 정도 커버가 되는 요소입니다. 즉, 최소한의 '글빨'만 갖춘다면 합/불을 뒤집을 만큼의 중대한 사항은 아니라는 것입니다. 그럼에도 불구하고 마지막으로 '글빨'에 대해서 이야기하는 이유는, 자기소개서처럼 목적이 있는 글을 쓰는 것이라면 최소한의 글쓰기 능력이 필요하기 때문입니다. 맞춤법이나 문장의 주/술어, 번역투, 반복되는 표현, 시제나 어미의 일치 등 몇 가지 기준을 두고 퇴고하면 피할 수 있는 실수들을 안 할 수 있습니다. 이를 위해서 "나를 잘 모르는, 혹은 자기소개서라는 것을 잘 모르는 사람들에게 내 글을 읽어달라고 했을 때 '이게 무슨 말이야?'라는 말이 나오지 않는다!"라는 기준을 세워보는 것은 어떨까요? 저의 글도 과연 명확하고 진정성이 담겼는가, 다시 한 번 읽어보게 되면서... 이 글을 읽는 분들께 조금이라도 도움이 되길 바래봅니다! 2월의 시작 힘차게 하시길 바랍니다! 우리 존재 화이팅! #앵커리어 #자기소개서 #꿀팁 #인사이트 #조언 #경험공유

기업문화 엿볼 때, 더팀스

로그인

/