스토리 홈

인터뷰

피드

뉴스

조회수 2407

어떻게 하면 더 와 닿을까?

2017년. 대한민국 기준 스마트폰 사용 인구 비율 88%(2016년 기준).스마트폰 사용자가 늘어난 만큼 스마트폰의 앱을 통해 손쉽게 상품을 구매하는 고객의 비율 또한 현저히 늘어났습니다. 이러한 현상은 새롭게 몇 가지의 포지션들에 주목하게 되었는데요. 그중 하나가 바로 '컨텐츠 디자인'입니다. 오프라인 또는 웹으로만 만날 수 있던 상품들을 이제는 앱으로 언제 어디서든 구매할 수 있게 되면서 그 상품을 매력적으로 보여주기 위한 '컨텐츠 디자인'의 영역이 너무나도 중요해진 것이죠.해서 이 글에서는 더욱 데일리스럽고, 고객에게 가독성이 좋은 '컨텐츠'를 전달하기 위해 노력하는 우리의 노력(!)을 보여드리려 합니다.문제의 시초다양한 형태로 표현되던 이벤트 페이지약 1여 년 전.. 위에 보시는 바와 같이 일관성 없이 과도하게 정보전달을 하고자 하는 성격이 컨텐츠에 녹아있었습니다. 더군다나 그렇다 한 데일리만의 일관성 있는 스타일도 없었죠. 해서 우리가 정말 고객에게 전달하고자 하는 방향이 무엇인지 생각하게 됩니다.데일리호텔 Creative LAB의 첫 번째 글(https://www.theteams.kr/teams/865/post/64504) '로고 제작기'에서도 확인할 수 있듯이 '더 나은 하루, 더 나은 삶을 위해'라는 사명 아래 '라이프 컨시어지 데일리'로 거듭나고자 하는 것이 우리의 목표였습니다. 해서 우리가 이 상품을 왜 추천하려 하는지의 감성적인 메시지와 그를 충분히 녹여낼 수 있는 부드러운 톤의 컨텐츠가 필요하다고 생각이 들었죠.컨텐츠 디자인첫 번째 리뉴얼.이벤트 페이지 첫번째 리뉴얼위 내용을 반영하여 이 같은 결과물이 나왔습니다. 기존보다는 훨씬 '라이프 컨시어지'에 가까운 성격의 컨텐츠 였지만 아직까지도 정보전달이 약하다는 피드백을 많이 받았죠. 그 이유는 바로 '가독성' 때문이었습니다. 첫 번째 리뉴얼을 진행할 당시 '가독성'의 영역보다는 비주얼을 좋게 개선해야 한다는 사명감 때문에 '심미성'에만 크게 신경을 쓰게 되어 디테일한 폰트 사이즈를 조정하지 못했던 이슈였습니다.때에 따라 달랐던 업장 설명 형태또한, 컨텐츠의 메인과 상단 부분은 개선이 되었다 쳐도 업장 설명 내용의 형태는 프로모션 성격에 따라 혹은 작업자의 취향에 따라 항상 변경되는 것도 큰 이슈였죠.더 나은 개선두 번째 리뉴얼.피드백에 힘입어, 폰트 사이즈와 컨텐츠 내에 적용되는 UI를 보완하는 두 번째 리뉴얼을 진행합니다. 분명 모니터에서 작업할 때는 충분히 크게 보이던 폰트 사이즈가 모바일로 확인했을 때는 작게 보였던 이슈를 해결하기 위해 폰트 사이즈 규정이 필요했습니다.그리고 앱 내에 들어가는 컨텐츠 디자인도 곧 UI의 일부이기 때문에 데일리호텔 앱 내에 사용되는 UI의 가이드를 반영해야 한다는 필요성을 느꼈습니다.실제 앱 구동시 UI개선된 이벤트 페이지 내의 업장 설명 부분이미지에서 확인할 수 있듯이 폰트 사이즈뿐만 아니라 업장과 업장 사이의 여백 부분과 CTA 버튼의 라운딩, 사이즈 등 디테일한 부분도 앱의 UI와 통일시켰죠. 이런 개선을 통해 앱을 사용하다가 이벤트 페이지로 들어왔을 때의 일관성을 유지시키고, 구매로 이어지는 경로의 어색함을 완충시켰습니다.현재 사용되어지는 컨텐츠 디자인의 톤앤매너더불어 앱내에서 고가의 호텔을 다루고 있기 때문에 진중하게 보다는 호텔도 쉽게 접할 수 있다는 느낌을 주기 위해서 톤도 한 층 밝게 리뉴얼 하였습니다.끝난 게끝난 게 아니다.말 그대로 끝난 게 끝난 게 아닙니다. 앞으로도 계속해서 고객의 새로운 니즈는 생길 것이고 그 니즈를 충족시킬 수 있도록 데일리는 끝없이 많은 부분을 업데이트하고 리뉴얼해야 할 것입니다.단순히 시각적으로 보기 좋은 디자인이 아니라, 사용자의 입장에서 이해하기 쉽고 편리한 디자인을 할 수 있도록 계속해서 노력하겠습니다! 감사합니다 :)기획/진행 : Creative팀작성자 : Creative팀 Blair Ahn#데일리 #데일리호텔 #디자인 #디자이너 #디자인팀 #고객중심 #인사이트 #경험공유 #후기 #일지
조회수 865

160330_페이스북 포스팅 복기

상황  설명스위처 배송 하루 전. 이번 포스팅을 하기 전에 남규가 페이스북을 통해 스위처 구매 방법과 관련된 내용을 포스팅하였다. 그 중 고객들이 가장 궁금해 하는 것은 렌탈 방식에 대한 자세한 설명. 이에 고객들의 궁금증을 해결해주기로 기획을 시작했다.컨텐츠 기획하루 전 이었기에 다양한 이슈가 있었다. '새로운 패키지', '1달 무료 사용 신청 페이지', '스위처 스펙' 등 포스팅을 할 다양한 요소가 있었지만 지난 컨텐츠의 댓글을 확인하면서 독자를 상상하고 컨텐츠를 기획했다.고객 의견렌탈 방식에 대해 자세히 알고 싶어하는 분들은 어떤 것을 가장 궁금해할까? 어디까지의 설명이 적절한 양일까?가장 궁금해 하는 것은 '돈' (이렇게 표현하니 이상하네)과 관련된 부분. 그래서 정확한 가격 설명과 '렌탈' 이라는 방식의 특성상 사용하다 반납하는 경우가 있기에, 이런 특이상황에 대해 설명을 드리는것이 최고라고 생각했다.문제는 이 렌탈 방식이 굉장히 변수가 많아 설명을 잘못하면 지루하고 무거울 수 있다는 것. 이에 최대한 친근하고 재밌게 설명을 하고자 했다. 또한, 렌탈 방식에 대해 거부감을 가지는 분들은 '매월 결제' 라는것에 대한 부담감을 가지고 계셨다. 이를 위해 '년'단위의 결제와 '자동' 결제에 대한 설명도 필요하다고 생각했다.컨텐츠 제작머리 아픈 숫자놀이위의 내용을 글로만 설명하면 너무 딱딱하고 지루 할 것 같아 "만화같이 표현해볼까?" 생각해서 그림도 그려보고 고민을 했는데, 저게 맞는건진 확인이 안 되었다. 다음에는 "이게 이해가 될까?" 싶은 부분을 예상 독자에게 보여주고 컨펌을 받으면 더 확실할 것 같다.플랜 비교표위의 사진은 실수한 부분을 수정한 이미지다. 멍청했다. 원래 할인율은 그냥 '10%', '20%', '30%'로 적혀있었다. 그걸 아무런 의심없이 그냥 사용했다. 포스팅하고 남규가 말해줘서 부랴부랴 수정했다.. 디테일한 부분을 잘 살려야 하는데 항상 실수하는 부분이라 다시 생각해보니 처참해진다.. 정신좀 차려야지.결과1.  like "56", shared "17", reached "14,060". 말도 안되는 도달율. 아마 권도균 대표님 덕분일 것이다. "oh.. god.."  shared를 보면 지인 분들과 기존부터 제품 구매를 원하셨던 분들이다. 아마 판매 전날이라 더 많이 기대하고 계셨던 것 같다.comment를 보면 "제품 판매"의 주제로 글을 쓰셨다. 컨텐츠 내용은 "스위처 판매합니다!"가 아니라 렌탈 방식에 대한 설명인데, 신기하다. 판매 '하루 전'이어서 그럴까? 아님 그 동안 우리가 만들어 온 '긴장감' 때문일까?2. 'like'의 수가 오르지 않는다.. 왜일까.. 이렇게 되면 도달율이 나오지 않아 광고를 걸어도 효과가 떨어질텐데.. 이번 달 부터는 광고 준비를 걸어야 할텐데, 빨리 '반응'을 높일 수 있는 방법을 찾아야겠다.#스위처 #Switcher #SNS마케팅 #SNS마케터 #일지 #페이스북 #페이스북마케팅 #마케터 #마케팅
조회수 886

중국 마케팅은 내 손안에! YDM차이나 '초언리'

안녕하세요, 매력만점의 옐로피플을 발굴해 소개하는 사내기자 Y의 인터뷰 그 16번째 이야기입니다! 이번 주인공은 바로 옐로디지털마케팅차이나에서 중국 마케팅을 담당하고 있는 초언리 대리입니다. 대륙의 그녀가 12년 전 낯선 한국 땅에 오게 된 계기는 바로 케이팝 때문이었다는데, 어떤 숨은 사연이 있을까요? 옐플의 첫 글로벌 옐로패밀리! 그녀의 이야기를 놓치지 마세요:)Y: 안녕하세요. 옐블 독자들을 위해 간략한 자기소개 부탁드려요:)안녕하세요, 옐블 독자 여러분! 옐로디지털마케팅차이나에서 중국 마케팅 운영을 담당하고 있는 초언리입니다. 반갑습니다:) Y: 옐플 인터뷰 사상 첫 외국인이세요! YDM차이나에서는 어떤 업무를 맡고 있나요? 영광입니다! YDM차이나에서 페이스북, 웨이보, 웨이신 등 다양한 SNS 채널을 운영하며 브랜드 마케팅을 담당하고 있습니다. 특히 요즘 한국을 찾는 중국 관광객들이 점점 많아지고 있는데, 그들을 타겟팅한 마케팅을 하는 거죠. 현재는 인천에 위치하고 있는 리조트를 담당하며 SNS 페이지를 만들어 중국인을 대상으로 프로모션 등의 마케팅을 진행하고 있습니다.Y: 마케팅이라는 직무를 선택하게 된 계기가 무엇인가요? 학생때부터 미디어 광고 분야에 관심이 많았습니다. 다양한 채널을 통해 다른 사람들에게 브랜드의 가치를 전달하는 일이 매력적으로 다가왔거든요. 그래서 한국으로 와 디지털미디어를 전공했고요. 졸업 후에는 한국에 오래 거주하며 체득한 현지 문화에 대한 이해도를 바탕으로 대중국 마케팅을 하면 잘 할 수 있을 거라는 생각이 들었습니다.Y: 한국어가 너무 유창하십니다! 한국에는 언제 오셨어요?고등학교를 졸업하고 2005년도에 한국에 처음 오게 됐어요. 대학을 여기서 졸업하고 일을 시작하고 보니 벌써 12년이 흘렀네요. 사실 고등학생때 유학이나 해외취업에는 전혀 관심이 없었습니다. 그런데 친구가 굉장한 케이팝 광팬이었어요. 친구에게 전파 당해서 케이팝에 빠져들게 됐고 한국 연예인을 보겠다는 일념으로 한국 유학을 결심하게 됐죠ㅋㅋㅋY: 오~ 어떤 연예인인지 여쭤봐도 될까요? 신화요♥ 12년부터 신화창조로 활동하고 있고 팬싸인회랑 콘서트도 꾸준히 가고 있어요! :)Y: YDM과는 어떻게 인연이 닿게 되었나요? 이전 직장에서 블로그 마케팅을 할 때 ‘위드블로그’와 마케팅 파트너로 일했어요. 이를 계기로 옐로스토리라는 회사를 알게 되었고 옐로스토리 안에 중국 마케팅팀이 있다는 사실을 알고 지원하게 됐습니다. 하고 싶었던 일 하면서 즐겁게 일하고 있어요:) Y: 특별한 취미나 사회경험이 있나요?직원분들을 대상으로 중국어를 가르치고 있어요ㅎㅎ 일주일에 한 번, 원하는 분들을 대상으로 수업을 진행하고 있는데, 보람도 있고 사람들과 친해질 기회도 많은 것 같아 좋습니다. 처음에는 중국어를 아예 못하던 분들이 저를 통해 배우면서 어느 정도 의사소통이 되는 것도 매우 보람있고 신기해요.Y: 중국어 수업! Y도 좀 듣고 싶네요 ㅠㅠ 나중에 기회가 된다면 언제든 환영입니다!! +_+Y: 일하면서 가장 보람을 느끼는 순간은 언제인가요? 브랜드 마케팅을 위해 페이지를 새로 개설해 운영을 담당했어요. 콘텐츠 관리부터 프로모션 기획까지 페이지에 많은 공을 들였는데, 어느 순간 팔로워수가 1만명이 넘어가더니 최근에는 7만명을 달성했어요. 가장 보람을 느낀 순간인 것 같아요.Y: 입사 후 가장 기억에 남는 재미있는 에피소드가 무엇인가요? 지난 12월 옐로스토리에서 연말 행사를 했습니다. 각 팀마다 장기자랑을 해서 이긴 팀에게 상품을 나눠주는 자리를 가졌어요. 모두가 퇴근한 후 사내카페에서 춤 연습을 하고 노래방에 가서 노래연습을 하는 등 그 준비 과정이 너무 즐거웠습니다. ㅎㅎY: 어떤 무대를 준비하셨는지 궁금합니다!!반전 무대를 준비했죠ㅋㅋㅋ 처음에는 여자 팀원들 셋이서 치파오를 입고 중국 발라드를 열창하다가 갑자기 남자 팀원 셋이 무대로 난입(?)하면서 박진영의 ‘허니’에 맞춰 춤을 췄어요. 세상에, 치파오를 입고 ‘허니’를 추는게 왜 그렇게 어렵던지ㅋㅋㅋ 아무튼 그 무대로 3등을 해서 상도 받았답니다! Y: YDM차이나와 함께 하면서 좋은 점은 무엇인가요? 한국인 직원들과 중국인 직원들이 서로 문화에 대한 이해도가 높고 새로운 문화에 대해 배우려는 자세가 정말 좋아요. 특히 장대규 대표님이 중국 직원들이 업무를 하는데 있어서 많은 도움을 주시면서 업무 적응 하는데 큰 역할을 해주고 계시죠:) Y: 앞으로는 어떤 일을 해보고 싶으세요? 마지막으로 옐로가족들에게 전하는 말씀도 부탁드립니다.현재는 리조트 분야만 담당하고 있지만 앞으로는 코스메틱 분야도 담당해보고 싶어요! 그리고 꾸준히 배워서 중국 마케팅 분야에 꼭 필요한 전문 인력이 되고 싶습니다. 앞으로도 잘 성장해 나갈테니 YDM차이나와 제가 함께 성장하는 모습 계속해서 지켜봐 주세요. 새해 복 많이 받으세요! 新年快乐!!
조회수 1061

[비. 사.세 #8] 서로 응원하는 승리의 브이V, 그리고6월의 BNB DAY 주인공은 나야나!

안녕하세요 미나 입니다!오늘은 비.사.세 여덟번째 이야기 인데요.비투링크에서는 매 달 Surprise BNB DAY가 있답니다 :)여기서 BNB DAY 란? B2LiNKer N Breakfast Day 의 약자에요 :)단순하게 아침을 제공하는 날이 아닌, 모든 비투링커들이 함께 아침을 먹으면서대화할 수 있도록 하기 위한 스페셜한 날이랍니다!요렇게 같이 셀카도 찍으셔도.... 되지만!!!부끄러우실까봐 직접 사진을 찍어드립니다 (ㅋㅋㅋ)매 달 HR에서 준비하는 BNB DAY 테마가 있어요.이번 달에는 2017년 상반기에 수고한 비투링커들을 위해서로 응원 + 승리를 의미하는 쁘이 (V) 미션입니다!♥ HR 지현님의 BNB DAY 잔디는 항상 출근길을 설레이게 합니다 ♥6월의 메뉴는 서브웨이!!!!자! 다같이 비투링커들의 6월 BNB DAY 사진 구경하시죠 :)V 귀엽고 발랄하게 쁘이 V치열한 경쟁을 뚫고 올라온 BEST PHOTO AWARD! :)남여 부문 입니다 (ㅋㅋㅋ)젤 오른쪽에 6월의 비투링커로 선정된 제가님이 보이시네요!* 제가님 인터뷰는 곧~ 보실 수 있습니다! *여여 부문 ^_^남남 부문 :) 다들 상큼하시네여그리고, MIX 부문 (ㅋㅋㅋ)그렇게 모든 비투링커들은 배부르고 기분좋은 월요일을 보내고 있다고 합니다 :)BNB DAY는 계속됩니다 :)#비투링크 #기업문화 #조직문화 #사내문화 #회사자랑 #팀자랑 #회사소개 #팀문화
조회수 1477

조직문화의 본질

조직문화가 화두다.예전에는 회사를 고를 때 급여나 회사 타이틀 같은 조건이 가장 중요했다. 그러나 이제는 점점 조직문화를 가장 중요시 여기는 추세다. 젊은 청년들은 점점 돈을 조금 적게 벌더라도 조직문화가 좋고 워라벨이 보장되는 곳을 선호하고 있다. 중장년층도 매일 빡빡하고 답답한 회사생활보다 좀 더 마음이 편한 곳을 찾고 있다.많은 직장인들의 퇴사 이유 중 가장 큰 부분도 조직문화라고 한다. 매주 월요병에 시달리는 이유도, 매일 아침 출근길이 무거운 이유도 대부분 조직문화 때문이다.      그렇다면 도대체 조직문화란 무엇일까? 대관절 조직문화란 무엇이기에 이렇게 모든 직장인들이 집중하고 신경쓰며, 많은 언론과 미디어에서도 조직문화가 바뀌어야 한다고 입을 모아 주창하는 것일까?사실 ‘조직문화’는 그 중요성에 비해 실체가 모호한 단어이다. 우선 ‘조직’과 ‘문화’라는 단어 자체가 어렵다. 보통 우리는 ‘조직’이라는 말을 잘 쓰지 않는다. “나 내일 회사 출근해”라고 말하지 “나 내일 조직 출근해”라고 말하지 않는다. 즉 조직은 회사를 말하는 것이다.      그렇다면 ‘문화’란 무엇인가? 이건 더 어려운 개념이다. 네이버 지식백과에는 ‘문화란 인간에게만 있는 생각과 행동 방식 중 사회 구성원들로부터 배우고 전달받은 것들로서 의식주, 언어, 풍습, 종교, 학문, 예술, 제도 등을 모두 포함한다’고 말한다.그렇다면 이것을 회사에 접목한다면, 회사 생활에서의 집단 내에서 배우고 전달되는 것들로서 회사의 의식주(복장, 사내식당, 사무실) 및 회사 보고 언어, 업무 방식, 회사의 비전과 철학, 규정 등이 모두 포함될 것이다.      이렇게 본다면, 한마디로 조직문화는 ‘회사에서 보내는 모든 삶’을 의미한다. 즉 조직문화란 여러 가지 회사 생활의 요소 중 하나가 아니라, 회사생활의 모든 것을 뜻하는 것이다.과거에는 모두가 다 회사에 개인을 맞추는 비슷한 생활 양식을 보였기 때문에 조직문화라는 것을 구분하거나 인식할 겨를이 없었다. 그러나 이제는 개인이 살아나는 다양성의 시대이다. 워라벨이니 퇴사니 하는 단어가 유행하기 시작한 것도 본질은 같다. 보다 다양하고 다채로운 개인의 삶이 ‘인식’되면서 원래 인간으로서 당연히 추구할 ‘행복한 일’을 추구하고 싶은 것이다.      ‘문화(Culture)’의 어원은 라틴어로 ‘경작하다, 마음을 돌보다’라는 뜻의 ‘Cultus’에서 유래했다고 한다. 즉, 제대로 조직문화를 이해하기 위해서는 사람의 '마음'을 돌보는 자세가 필요하다.     그러나 현재까지 대부분의 기업에서 조직문화를 다루는 방식은 겉핥기식이다.조직문화를 혁신한다고 반바지 허용, 염색 가능 등 복장 자율화를 추진하지만 누군가는 눈치를 주고 또 눈치를 본다. 진짜 자유로운 조직은 '복장'에 대한 규정조차 없다. 신경도 쓰지 않는 것이다. 복장이 자율이라고 자랑하는 것은 여전히 복장에 눈치를 보고 있다는 반증이다.  회사 사내 식당에서 최고급 음식이 나오지만 상사와 함께 먹다보면 속이 체한다. (살만찐다)구글처럼 창의적이고 쾌적한 휴게공간을 만들었지만 아무도 그 곳에서 맘 놓고 쉬지 못한다.직급을 파괴하고 호칭을 그냥 '님' 자로 편하게 통일하지만, 부장님께 XX님 이라고 말하기 불편해 아예 아무런 호칭도 부르지 않는다고 한다. 이메일에도 그냥 '안녕하세요'만 쓰고, 아무런 호칭을 부르지 않는다.자율출퇴근과 연차/휴직 보장 제도를 만들지만 정작 남들 눈치 보느라 쓰지 못한다. 칼퇴근을 한다고 저녁 6시 정각에 PC를 끄고 불이 꺼지고 문이 닫히지만, 그러면 그 일을 그대로 집에 가져가서 해야 한다.그러면서 외부적으로는 ‘자율적이고 창의적인 조직문화 혁신’을 만들었다고 대서특필한다. 조직문화의 '형식'에만 치중하는 것이다.      물론 이러한 형식적인 조건들도 중요하다. 당연히 어느 정도 필요하다.그러나 조직문화의 진짜 본질은 '마음'이다.그리고 그 마음을 돌보는 역할은 '리더'가 해야 한다. 즉 사람들을 돌보고 신뢰를 줄 수 있는 리더의 책임이 절대적인 것이다.      혹자는 조직문화를 모두가 함께 만들어간다고 말한다. 틀린 말은 아니다. 그러나 아무리 구성원들이 열심히 해도 리더가 말 한마디 '안돼'라고 말하면 모든 게 물거품이다. 결국은 최종 의사결정권을 가진 리더의 역할이 막중하다고 할 수 있다. 리더를 변화시켜야 한다. 리더를 변화시킬 수 있는 리더들의 리더 (맨 윗분들)들이 먼저 변하고 결단해야 한다. 그렇지 않고 그냥 외부 컨설팅이나 인사팀에게 시켜서 몇 개월간 프로젝트 돌리고 나서 한 번 보고서 만들어와 봐 하고, 그 보고만 받고 흉내만 낸다면 여전히 조직문화의 혁신은 요원할 것이다.최근 ‘조직문화 혁신 TF’를 신설하고 인사팀에서도 적극 챙기는 등 기업 전반적으로 조직문화에 대한 관심이 더 커지고 있다. 이러한 흐름을 잘 살려서 부디 형식적인 허례허식이 아닌, 진짜 변화할 수 있는 조직문화를 만들 수 있기를 진심으로 희망한다.#퇴사학교 #조직문화 #인사이트
조회수 4171

파이썬 코딩 컨벤션

스포카 개발팀 문성원입니다. 저희는 (익히 아시다시피) 서버를 개발하는데 파이썬(Python)을 사용하고 있는데, 오늘은 이러한 파이썬 코드를 작성할 때 기준이 되는 코딩 컨벤션(Coding Convention)에 대해서 알아보겠습니다.Coding Convention코딩 컨벤션이란 개념에 대해 생소하신 분들도 계실 테니 이를 먼저 알아보죠. 코딩 컨벤션은 프로그램 코드를 작성할 때 사용되는 일종의 기준입니다. 이를테면 들여쓰기(Indentation)는 공백으로 할거냐 탭으로 할거냐. 부터 var a = 3; 과 같은 코드에서 a와 =를 붙이느냐 마느냐라던지를 정해주는 것이죠. 알고 계시는 것처럼 이러한 차이는 특별히 실행 결과의 영향을 주지 않습니다. 다르게 이야기하자면 “실행 결과에 별 차이가 없는 선택지들”이기 때문에 일관성이 있는 기준을 두어 통일하자는 것이지요.그렇다면 왜 이런 선택지를 통일해야 할까요? 불행히도 우리가 작성한 코드는 많은 사람들이 보게 됩니다. 같이 일하는 동료, 이바지하고 있는 프로젝트의 리뷰어, 심지어 내일의 자기 자신까지도 말이죠. 그런데 이런 많은 사람들이 우리가 코드를 작성할 때 했던 선택지를 일일이 추론해서 이해하는 건 굉장히 피곤하고 짜증 나는 일입니다. 그래서 우리는 사소한 것부터 일종의 규칙을 정해서 이런 짜증과 불편함을 줄이려는 겁니다. 또한, 일반적으로 좋은 기준에는 훌륭한 프로그래머들의 좋은 습관이 배어있기 때문에 더 나은 품질의 코드를 작성하는 데에도 많은 도움이 됩니다.이런 코딩 컨벤션은 극단적으로 이야기하면 프로젝트마다 하나씩 존재한다고 볼 수도 있지만, 일반적으로 그 언어문화를 공유하는 공동체에서 인정하는 컨벤션은 대부분 통일되어 있습니다. 파이썬은 지금부터 살펴볼 PEP 8이 대표적입니다.PEP?PEP(Python Enhance Proposal)이란 이름대로 본디 파이썬을 개선하기 위한 개선 제안서를 뜻합니다. 이러한 제안서는 새로운 기능이나 구현을 제안하는 Standard Track, (구현을 포함하지 않는) 파이썬의 디자인 이슈나 일반적인 지침, 혹은 커뮤니티에의 정보를 제안하는 Informational, 그리고 파이썬 개발 과정의 개선을 제안하는 Process의 3가지로 구분할 수 있습니다. (좀 더 자세한 사항은 PEP에 대해 다루고 있는 PEP인 PEP 1을 참고하세요.) 파이썬은 언어의 컨벤션을 이러한 제안서(Process)로 나타내고 있는데 이것이 바로 PEP 8입니다.Laplace’s Box기본적으로 가이드라인이니만큼 규칙만 빽빽할 것 같지만, PEP 8는 서두부터 예외를 언급한 섹션이 있습니다.A style guide is about consistency. Consistency with this style guide is important. Consistency within a project is more important. Consistency within one module or function is most important.스타일 가이드는 일관성(consistency)에 관한 것입니다. 이 스타일 가이드의 일관성은 중요하죠. 하지만 프로젝트의 일관성은 더욱 중요하며, 하나의 모듈이나 함수의 일관성은 더더욱 중요합니다.But most importantly: know when to be inconsistent – sometimes the style guide just doesn’t apply. When in doubt, use your best judgment. Look at other examples and decide what looks best. And don’t hesitate to ask!하지만 가장 중요한 건 언제 이것을 어길지 아는 것입니다. – 때때로 스타일 가이드는 적용되지 않습니다. 의심이 들 때는 여러분의 최선의 판단을 따르세요. 다른 예제를 보고 어느 게 제일 나은지 골라야 합니다. 질문을 주저하지 마세요!Two good reasons to break a particular rule:When applying the rule would make the code less readable, even for someone who is used to reading code that follows the rules.To be consistent with surrounding code that also breaks it (maybe for historic reasons) – although this is also an opportunity to clean up someone else’s mess (in true XP style).다음은 규칙들을 어기는 2가지 좋은 예외 사항입니다.규칙을 적용한 코드가 (규칙을 숙지한 사람 눈에도) 읽기 어려운 경우일관성을 지키려고 한 수정이 다른 규칙을 어기는 경우(아마도 역사적인 이유겠죠.)아직 아무것도 안나왔는데 좀 이르다구요?It’s all about common sense예외 규정을 보여주며 시작하는 PEP 8이지만 얼개는 그리 복잡하지도 않고 크게 난해하지도 않습니다. 여기서는 대표적인 몇 가지만 추려서 소개하겠습니다.Code lay-out들여쓰기는 공백 4칸을 권장합니다.한 줄은 최대 79자까지최상위(top-level) 함수와 클래스 정의는 2줄씩 띄어 씁니다.클래스 내의 메소드 정의는 1줄씩 띄어 씁니다.Whitespace in Expressions and Statements다음과 같은 곳의 불필요한 공백은 피합니다.대괄호([])와 소괄호(())안쉼표(,), 쌍점(:)과 쌍반점(;) 앞키워드 인자(keyword argument)와 인자의 기본값(default parameter value)의 = 는 붙여 씁니다.Comments코드와 모순되는 주석은 없느니만 못합니다. 항상 코드에 따라 갱신해야 합니다.불필요한 주석은 달지 마세요.한 줄 주석은 신중히 다세요.문서화 문자열(Docstring)에 대한 컨벤션은 PEP 257을 참고하세요.Naming Conventions변수명에서 _(밑줄)은 위치에 따라 다음과 같은 의미가 있습니다._single_leading_underscore: 내부적으로 사용되는 변수를 일컫습니다.single_trailing_underscore_: 파이썬 기본 키워드와 충돌을 피하려고 사용합니다.__double_leading_underscore: 클래스 속성으로 사용되면 그 이름을 변경합니다. (ex. FooBar에 정의된 __boo는 _FooBar__boo로 바뀝니다.)__double_leading_and_trailing_underscore__: 마술(magic)을 부리는 용도로 사용되거나 사용자가 조정할 수 있는 네임스페이스 안의 속성을 뜻합니다. 이런 이름을 새로 만들지 마시고 오직 문서대로만 사용하세요.소문자 L, 대문자 O, 대문자 I는 변수명으로 사용하지 마세요. 어떤 폰트에서는 가독성이 굉장히 안 좋습니다.모듈(Module) 명은 짧은 소문자로 구성되며 필요하다면 밑줄로 나눕니다.모듈은 파이썬 파일(.py)에 대응하기 때문에 파일 시스템의 영향을 받으니 주의하세요.C/C++ 확장 모듈은 밑줄로 시작합니다.클래스 명은 카멜케이스(CamelCase)로 작성합니다.내부적으로 쓰이면 밑줄을 앞에 붙입니다.예외(Exception)는 실제로 에러인 경우엔 “Error”를 뒤에 붙입니다.함수명은 소문자로 구성하되 필요하면 밑줄로 나눕니다.대소문자 혼용은 이미 흔하게 사용되는 부분에 대해서만 하위호환을 위해 허용합니다.인스턴스 메소드의 첫 번째 인자는 언제나 self입니다.클래스 메소드의 첫 번째 인자는 언제나 cls입니다.메소드명은 함수명과 같으나 비공개(non-public) 메소드, 혹은 변수면 밑줄을 앞에 붙입니다.서브 클래스(sub-class)의 이름충돌을 막기 위해서는 밑줄 2개를 앞에 붙입니다.상수(Constant)는 모듈 단위에서만 정의하며 모두 대문자에 필요하다면 밑줄로 나눕니다.Programming Recommendations코드는 될 수 있으면 어떤 구현(PyPy, Jython, IronPython등)에서도 불이익이 없게끔 작성되어야 합니다.None을 비교할때는 is나 is not만 사용합니다.클래스 기반의 예외를 사용하세요.모듈이나 패키지에 자기 도메인에 특화된(domain-specific)한 기반 예외 클래스(base exception class)를 빌트인(built-in)된 예외를 서브클래싱해 정의하는게 좋습니다. 이 때 클래스는 항상 문서화 문자열을 포함해야 합니다.class MessageError(Exception): """Base class for errors in the email package."""raise ValueError('message')가 (예전에 쓰이던) raise ValueError, 'message'보다 낫습니다.예외를 except:로 잡기보단 명확히 예외를 명시합니다.(ex. except ImportError:try: 블록의 코드는 필요한 것만 최소한으로 작성합니다.string 모듈보다는 string 메소드를 사용합니다. 메소드는 모듈보다 더 빠르고, 유니코드 문자열에 대해 같은 API를 공유합니다.접두사나 접미사를 검사할 때는 startswith()와 endwith()를 사용합니다.객체의 타입을 비교할 때는 isinstance()를 사용합니다.빈 시퀀스(문자열, 리스트(list), 튜플(tuple))는 조건문에서 거짓(false)입니다.불린형(boolean)의 값을 조건문에서 ==를 통해 비교하지 마세요.Give me a reason하지만 몇몇 규칙은 그 자체만으론 명확한 이유를 찾기 어려운 것도 있습니다. 가령 예를 들면 이런 규칙이 있습니다.More than one space around an assignment (or other) operator to align it with another.Yes:x = 1 y = 2 long_variable = 3No:x = 1 y = 2 long_variable = 3보통 저런 식으로 공백을 통해 =를 맞추는 건 보기에도 좋아 보입니다. 하지만 변수가 추가되는 경우에는 어떨까요. 변수가 추가 될때마다 공백을 유지하기 위해 불필요한 변경이 생깁니다. 이는 소스를 병합(merge)할 때 혼란을 일으키기 쉽습니다.언뜻 보면 잘 이해가 안 가는 규칙은 이런 것도 있습니다.Imports should usually be on separate lines, e.g.:Yes: import os import sys No: import sys, os굳이 한 줄씩 내려쓰면 길어지기만 하고 보기 안 좋지 않을까요? 하지만 이 역시 대부분의 변경 추적 도구가 행 기반임을 고려하면 그렇지 않습니다.#스포카 #개발 #파이썬 #개발자 #Python #컨벤션 #이벤트참여 #이벤트후기 #후기
조회수 1141

라이더소개#11. 국대 앞의 사나이, 데니

[라이더소개#11. '국대(떡볶이)' 앞의 사나이, 데니]데니을 소개합니다 :)Q. 간단한 자기소개 부탁해내 닉네임은 데니고,나이는93년생 닭띠,유학생이야. 현재 한국에 나와서 지금 이렇게 아띠인력거를 접하고, 일을 하고 있는6개월 차 라이더야.Q. 어떻게 아띠인력거를 시작하게 됐어?계기가 있어?맨 처음에 일을 시작하게 된 계기는,김난도 선생님의 책을 읽다가IJ가 자전거 고치는 모습을 보고서'아 이거 왠지 느낌있다'싶어서 시작하게 됐어. '재밌게 일하고 싶다' 그런 마인드가 나랑 약간 생각이 비슷하더라고.그때가 한국오기 며칠 전이었어.타이밍이 잘 맞았지.Q. 처음 라이딩 했을 때 어땠어?진짜 좋았어.진짜 재밌었어.첫 날 라이딩하고, '아 적성을 찾았구나'싶었어.(웃음) 처음에 온이랑 같이 나가서 빈 차로 따라다니는건 힘들어서 재미없었는데,처음으로 프리라이딩 했을 때는 진짜 재미있었어. 그 때 어떤 여고생들을 태웠었는데,같이 어우러지는 게 너무 좋았어.그 친구들은 아직도 기억나.얼굴도 기억나고.Q. 라이더를 하면서 가장 힘들 때는 언제야?진짜 춥거나, 아니면진짜 무겁거나.하루는 영하20도에 외국인 두분이 탔었는데,그 때는 진짜 춥고,진짜 무거웠던 날이었어.. 심지어 예약도 그거 하나밖에 없어서 좀 힘들었지..음. 근데 오히려 힘든 건,빈차로 계속 있을 때?멘탈적으로 그게 더 힘들지.Q. 가장 기억에 남는 손님은 어떤 손님이야? 기억에 남는 손님은 너무 많지~음, 어떤 누님들이 탄 적이 있는데 진짜 웃겼어.안국역에서 삼청동 수제비 집까지 태워드렸는데, 그 때 진짜 추운 날이었거든.차양 씌운 인력거를 타고있었고,너무 추워하시는 게 보여서 내가'춥죠?타실래요?제가 태워드릴게요.'하니까 '빨리 태워줘요!!'이러시는 거야.(웃음) 거기서부터 약간 웃긴 느낌이 났는데,태워드리고 나서는'수제비 같이 먹을래요?먹고가요!'하고 시크하게 물어보셔서 수제비도 같이 먹었어. 먹으면서는 몇 살인지 물어보시더니 그때부터 말을 놓으시더라고.(웃음) '맛있지?많이 먹어~'하시면서. 그리고 또 밥 먹고 나서는 자연스럽게 인력거에 타시더니'커피 마시러 가자~커피 사줄게!'이러시더라고.(웃음) 근데 그게 막 기분 나쁘지 않게, 정말 친 누나처럼 대해주셨어.그리고 서촌 아트갤러리까지 데려다 드리니까'우리 이제 헤어지는 거냐~'이러시면서 아쉬워하는 모습이 보였는데,그 때가 기억에 남아.그리고 또.. 생각하면 계속 나와!오늘같은 경우도 기억에 남지. 그림 그려주시는 분이랑 콜라보레이션해가지고 1시간 동안 같이 타면서 그림도 그리고.아,그것도 기억에 남는다.생일날 혼자서 타러 오신 남자 분!! 짠해서 기억에 남아 그 분...사진 찍어달라고 보통 핸드폰 주는데,그 분은 아이패드를 줘서 내가 막 사진 찍어드리고.. 일부러 오히려 당연한 척,아무렇지 않은 척하면서 태워드렸었어.(웃음)예약자분 성함이 중성적인 이름이어서 혹시 여자분 혼자면 외로울 테니까 조쉬(인형)도 챙겨가고 그랬는데..(웃음) 근데 그 때 마침 한 달에 한 번 헌법재판소 하늘공원이 오픈 되는 날이었어. 그 때 딱 오셔가지구 거기 갔었던 기억이 있어.그리고.. 케빈이랑 서촌에서 라이딩했을 때 유쾌하신 어머님들도 생각난다.사진 찍지마,찍지마 하셨는데 찍고 나니까 제일 환하게 웃고 계시ㄷ더라.(웃음) 초등학생 남자 꼬마 한 명도 기억나고... Q. 우리가3개 정도의 코스가 있잖아.어떤 코스를 제일 좋아해?아, 그건 어려운 질문이다..엄마가 좋냐,아빠가 좋냐지.다 좋아!근데 제일 안 좋아하는 걸 꼽으라면 오히려 제일 많이 하는 서북촌일 것 같아. 늘 하는거라서.그래서 가끔씩 히스토리코스를 하면 기분이 좋아.다 매력이 다른 것 같아.서북촌은 늘 하는거라서 시간관리가 칼같이 되는데,서촌은 혼자하면 시간관리가 잘 안돼.Q. 왜 인력거를 선택한 거야?미국에 있으면서 한국 사람들이 그리웠어.사람들을 많이 만나고 싶었어.그거에 최적화된 딱 맞는 일이잖아. 이야기도 많이 할 수 있고.그런 일을 찾고 있었지.Q. 대니의 개인적인 꿈은 뭐야?요새 내가 느끼는 건데 정해진 꿈이 없어. 그래서우선 지금은 꿈을 찾는 게 꿈이야.그리고 인력거 일을 하면서 느끼는 건데,이쪽의 일을 하는 게 나한테 맞는 것 같아. 이게 내 장점인 것 같은데 이걸 살릴 수 있는 일을 찾아봐야지.Q. 아띠의 자랑을 하자면?우선, '편하다'라는 거.정말 심플한 건데 엄청난 장점인 것 같아.그것 만큼 좋은 게 어디 있어. 일하면서 편한 사람이 얼마나 있겠어.그리고 힘든 것도 없어. 다른 데에서 일할 때는10분마다 시계보고 언제 퇴근하지~그랬는데, 여기서는 시계 보면'빨리 복귀 해야 되는데,더 타고 싶다!'이렇게 돼.'오늘 어떻게 시간 보내지'하면 벌써7시가 되어있고.(웃음)그리고 아띠는 남성미가 넘치지!(웃음)Q. 아띠가 어떤 모습으로 나아갔으면 좋겠어?지금의 이 모습을 잊지 않았으면 좋겠어.라이더가 많아지고 인력거도 많아지고 그러다 보면,지금 아띠의 분위기를 더 잘 유지해야 될 것 같아.Q. 너에게 아띠인력거란?뜻밖에 만난 행운?진짜 이걸 하게 될지 몰랐는데,진짜 잘한 것 같아. 6개월 정도 했는데,몇 년 뒤에 생각해도 정말 잘했다고 생각할 것 같아.Q. 미래의 아띠라이더들에게 한마디 한다면?만약에 돈을 벌 생각으로 하려 한다면 하지 말라고 하고 싶어.그런 생각이면 아띠를 할 수 없어.진짜 즐기려고 해야 할 수 있어.나는 항상 내가 재미있어야 사람들을 재미있게 해줄 수 있다고 생각하거든.진짜 즐겁게 일하고 싶은 사람만 오라고 하고 싶어.근데 후유증은 너무 빠져버리면 안 된다는 거야!(웃음)Q. 며칠 뒤면 미국으로 돌아가는데,기분이 어때?아쉽다~ 데니!괜찮아~ 언젠가 또 오겠지.만약 돌아와서 다시 라이딩을 하면 내가 처음 라이딩 하면서 느꼈던 감정을 또 느낄 수 있을 것 같아.그 때 저스틴,현아,나 이렇게 셋이서 경복궁 쪽으로 출근하면서 쫙 나갔는데 그 때 진짜 기분 좋았거든. 그리고 그 날 수학여행 온 애들이 단체로 있었는데,내가 혼자 신나가지고 손 흔드니까,'꺄!'하면서 진짜 말도 안 되는 반응이 나와가지고되게 기분 좋게 탔었어.(웃음)Q. 지금까지 아쉬웠던 점이 있을까?R2가 못된 게 진짜 아쉬워.이왕 하는 거R2는 찍어야 나중에 인력거 탔다고 할 수 있는데... 그리고 내가 아끼는 신발, 인력거 체인 때문에 더러운 거 묻었는데 어떻게 배상해줄 거야? 라이딩 하는 첫날에'이왕 타는 거 신발 멋있는 거 신고 타야지~' 했는데..첫날부터!!! (웃음)Q. 마지막으로 하고 싶은 말이 있으면 해줘나중에 돌아왔을 때 아띠가 많이 안 변했으면 좋겠어.정비사만 고용하지 말고,주기적으로 근육마사지 받을 수 있게 마사지사도 고용해서 번호표같은 거 뽑아서 마사지 받게 하면 좋을 것 같아!라이더들이 항상 풀컨디션으로 있을 수 있게.(웃음웃음)그리고 스포츠적으로 접근해서 라이더들 유니폼 맞춰서 등번호 제도 같은 거 도입하면 재미있을 것 같아.난42번.나중에 만든다면42번으로 만들어서 내 유니폼 걸어줘.내가 항상 국대 앞에 있는 자세로 동상도 세워서!(웃음)언제나 유쾌한 데니의 인터뷰였습니다!미국으로 조심히 돌아가길 바라며, 다시 학생으로 돌아가는 데니를 응원하며,인터뷰를 마칩니다:)#아띠라이더스클럽 #팀원소개 #팀원인터뷰 #팀원자랑 #기업문화 #조직문화 #사내문화
조회수 1324

레진 기술 블로그 - 자바 기반의 백엔드와의 세션 공유를 위한 레일즈 세션 처리 분석

레일즈 기반의 프론트엔드(브라우저에서 서버 사이드 렌더링 계층까지)와 자바 기반의 백엔드(내부 API와 그 이후 계층)이 세션을 공유하기 위해 먼저 레일즈의 세션 처리 과정을 분석하고, 레일즈 세션 쿠키를 다루기 위한 자바 소스 코드를 공유합니다.여기저기 자랑하고 다녔으니 아시는 분은 아시다시피 레진은 구글앱엔진을 사용하고 있습니다. 지금이야 Java, Python, Node.js, Go 언어와 Flexible Environment 같은 다양한 선택지가 있지만, 레진이 입주할 당시만 해도 Java 7(subset), Python(subset)을 지원하는 Standard Environment라는 선택지 밖에 없었죠.최근 Saemaeul Undong 기술 부채 탕감의 일환으로 자바7, 스프링3.x, JSP(!) 기반의 백엔드에 포함되어 있던 프론트엔드를 레일즈 기반의 프론트엔드 서버(서버 사이드 렌더링을 담당하는 서버는 프론트일까요? 백엔드일까요?)로 분리하고 있습니다.서로 다른 세계의 존재들 - 자바와 레일즈의 세션을 공유해야하는 상황이 문제의 발단입니다.자바와 레일즈의 세션을 공유하는 여러가지 방법이 있겠지만, 가장 단순하고 효과적인 방법은 쿠키(cookie)라고 판단하고, 세션 encrypt/decrypt와 marshal/unmarshal을 동일한 방식으로 맞추기로 했습니다. (백엔드 API를 완전히 stateless하게 새로 만들면 좋겠지만, 코인은 벌어야 소는 키워야죠)이를 위해 레일즈의 세션 처리 과정을 분석하고 정리했습니다.레일즈의 actionpack의 action_dispatch/middleware/cookie.rb를 보면 EncryptedCookieJar 클래스의 초기화 과정은 다음과 같습니다(digest의 경우 따로 지정안하면 SHA1이 사용되는 듯):class EncryptedCookieJar < AbstractCookieJar # :nodoc: include SerializedCookieJars def initialize(parent_jar) super if ActiveSupport::LegacyKeyGenerator === key_generator raise "You didn't set secrets.secret_key_base, which is required for this cookie jar. " + "Read the upgrade documentation to learn more about this new config option." end secret = key_generator.generate_key(request.encrypted_cookie_salt || '') sign_secret = key_generator.generate_key(request.encrypted_signed_cookie_salt || '') @encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, digest: digest, serializer: ActiveSupport::MessageEncryptor::NullSerializer) end private def parse(name, encrypted_message) debugger deserialize name, @encryptor.decrypt_and_verify(encrypted_message) rescue ActiveSupport::MessageVerifier::InvalidSignature, ActiveSupport::MessageEncryptor::InvalidMessage nil end def commit(options) debugger options[:value] = @encryptor.encrypt_and_sign(serialize(options[:value])) raise CookieOverflow if options[:value].bytesize > MAX_COOKIE_SIZE end end key_generator는 EncryptedCookieJar에 포함된 SerializedCookieJars 모듈에 정의되어 있습니다:module SerializedCookieJars # ... def key_generator request.key_generator end end 흠… 좀 더 파보죠. request.key_genrator는 다음과 같습니다:class Request # ... def key_generator get_header Cookies::GENERATOR_KEY end #... end 흠… 좀 더 파야할 듯 ㅠㅠ.Cookies::GENERATOR_KEY는 다음과 같습니다:class Cookies #... GENERATOR_KEY = "action_dispatch.key_generator".freeze end action_dispatch.key_generator는 레일즈의 엔진 모듈에 해당하는 railties의 application.rb에 정의되어 있습니다:def key_generator # number of iterations selected based on consultation with the google security # team. Details at https://github.com/rails/rails/pull/6952#issuecomment-7661220 @caching_key_generator ||= if secrets.secret_key_base unless secrets.secret_key_base.kind_of?(String) raise ArgumentError, "`secret_key_base` for #{Rails.env} environment must be a type of String, change this value in `config/secrets.yml`" end key_generator = ActiveSupport::KeyGenerator.new(secrets.secret_key_base, iterations: 1000) ActiveSupport::CachingKeyGenerator.new(key_generator) else ActiveSupport::LegacyKeyGenerator.new(secrets.secret_token) end end # ... def env_config @app_env_config ||= begin validate_secret_key_config! super.merge( # ... "action_dispatch.key_generator" => key_generator, "action_dispatch.signed_cookie_salt" => config.action_dispatch.signed_cookie_salt, "action_dispatch.encrypted_cookie_salt" => config.action_dispatch.encrypted_cookie_salt, "action_dispatch.encrypted_signed_cookie_salt" => config.action_dispatch.encrypted_signed_cookie_salt, "action_dispatch.cookies_serializer" => config.action_dispatch.cookies_serializer, "action_dispatch.cookies_digest" => config.action_dispatch.cookies_digest ) end end 너무 깊이 판 느낌적느낌(?)이 있지만, 여기까지 왔으니 좀 더 파보겠습니다.핵심 알고리즘은 activesupport의 key_generator.rb, message_encryptor.rb, message_verifier.rb에 정의되어 있습니다.먼저, key_generator.rb의 핵심은 다음과 같습니다:class KeyGenerator def initialize(secret, options = {}) @secret = secret # The default iterations are higher than required for our key derivation uses # on the off chance someone uses this for password storage @iterations = options[:iterations] || 2**16 end # Returns a derived key suitable for use. The default key_size is chosen # to be compatible with the default settings of ActiveSupport::MessageVerifier. # i.e. OpenSSL::Digest::SHA1#block_length def generate_key(salt, key_size=64) OpenSSL::PKCS5.pbkdf2_hmac_sha1(@secret, salt, @iterations, key_size) end end 계속해서, message_encryptor.rb의 핵심은 다음과 같습니다:def initialize(secret, *signature_key_or_options) options = signature_key_or_options.extract_options! sign_secret = signature_key_or_options.first @secret = secret @sign_secret = sign_secret @cipher = options[:cipher] || 'aes-256-cbc' @verifier = MessageVerifier.new(@sign_secret || @secret, digest: options[:digest] || 'SHA1', serializer: NullSerializer) @serializer = options[:serializer] || Marshal end def _encrypt(value) cipher = new_cipher cipher.encrypt cipher.key = @secret # Rely on OpenSSL for the initialization vector iv = cipher.random_iv encrypted_data = cipher.update(@serializer.dump(value)) encrypted_data << cipher.final "#{::Base64.strict_encode64 encrypted_data}--#{::Base64.strict_encode64 iv}" end def _decrypt(encrypted_message) cipher = new_cipher encrypted_data, iv = encrypted_message.split("--".freeze).map {|v| ::Base64.strict_decode64(v)} cipher.decrypt cipher.key = @secret cipher.iv = iv decrypted_data = cipher.update(encrypted_data) decrypted_data << cipher.final @serializer.load(decrypted_data) rescue OpenSSLCipherError, TypeError, ArgumentError raise InvalidMessage end def encrypt_and_sign(value) verifier.generate(_encrypt(value)) end def decrypt_and_verify(value) _decrypt(verifier.verify(value)) end (Hopefully)마지막으로, message_verifier.rb의 핵심은 다음과 같습니다:def initialize(secret, options = {}) raise ArgumentError, 'Secret should not be nil.' unless secret @secret = secret @digest = options[:digest] || 'SHA1' @serializer = options[:serializer] || Marshal end def valid_message?(signed_message) return if signed_message.nil? || !signed_message.valid_encoding? || signed_message.blank? data, digest = signed_message.split("--".freeze) data.present? && digest.present? && ActiveSupport::SecurityUtils.secure_compare(digest, generate_digest(data)) end def verified(signed_message) if valid_message?(signed_message) begin data = signed_message.split("--".freeze)[0] @serializer.load(decode(data)) rescue ArgumentError => argument_error return if argument_error.message =~ %r{invalid base64} raise end end end def generate(value) data = encode(@serializer.dump(value)) "#{data}--#{generate_digest(data)}" end private def encode(data) ::Base64.strict_encode64(data) end def decode(data) ::Base64.strict_decode64(data) end def generate_digest(data) require 'openssl' unless defined?(OpenSSL) OpenSSL::HMAC.hexdigest(OpenSSL::Digest.const_get(@digest).new, @secret, data) end # ... # encode, decode는 base64사용 이제 레일즈가 쿠키 기반의 세션을 어떻게 처리하는지 조금 눈에 들어옵니다. 그러나 우리의 최종 목표는 레일즈의 내부를 공부하는 것이 아니라, 자바에서 동일한 처리를 하는 것입니다. 모듈 의존성 따위는 가볍게 무시하고 무한복붙(?)을 시전해서, 레일즈의 세션 처리 과정을 눈으로 확인할 수 있도록 재구성했습니다:require 'openssl' require 'base64' require 'concurrent/map' class Object def blank? respond_to?(:empty?) ? !!empty? : !self end def present? !blank? end end class Hash # By default, only instances of Hash itself are extractable. # Subclasses of Hash may implement this method and return # true to declare themselves as extractable. If a Hash # is extractable, Array#extract_options! pops it from # the Array when it is the last element of the Array. def extractable_options? instance_of?(Hash) end end class Array def extract_options! if last.is_a?(Hash) && last.extractable_options? pop else {} end end end module SecurityUtils def secure_compare(a, b) return false unless a.bytesize == b.bytesize l = a.unpack "C#{a.bytesize}" res = 0 b.each_byte { |byte| res |= byte ^ l.shift } res == 0 end module_function :secure_compare end class KeyGenerator def initialize(secret, options = {}) @secret = secret # The default iterations are higher than required for our key derivation uses # on the off chance someone uses this for password storage @iterations = options[:iterations] || 2**16 end def generate_key(salt, key_size=64) OpenSSL::PKCS5.pbkdf2_hmac_sha1(@secret, salt, @iterations, key_size) end end class CachingKeyGenerator def initialize(key_generator) @key_generator = key_generator @cache_keys = Concurrent::Map.new end # Returns a derived key suitable for use. def generate_key(*args) @cache_keys[args.join] ||= @key_generator.generate_key(*args) end end class MessageVerifier class InvalidSignature < StandardError; end def initialize(secret, options = {}) raise ArgumentError, 'Secret should not be nil.' unless secret @secret = secret @digest = options[:digest] || 'SHA1' @serializer = options[:serializer] || Marshal end def valid_message?(signed_message) return if signed_message.nil? || !signed_message.valid_encoding? || signed_message.blank? data, digest = signed_message.split("--".freeze) data.present? && digest.present? && SecurityUtils.secure_compare(digest, generate_digest(data)) end def verified(signed_message) if valid_message?(signed_message) begin data = signed_message.split("--".freeze)[0] @serializer.load(decode(data)) rescue ArgumentError => argument_error return if argument_error.message =~ %r{invalid base64} raise end end end def verify(signed_message) verified(signed_message) || raise(InvalidSignature) end def generate(value) data = encode(@serializer.dump(value)) "#{data}--#{generate_digest(data)}" end private def encode(data) ::Base64.strict_encode64(data) end def decode(data) ::Base64.strict_decode64(data) end def generate_digest(data) require 'openssl' unless defined?(OpenSSL) OpenSSL::HMAC.hexdigest(OpenSSL::Digest.const_get(@digest).new, @secret, data) end end class MessageEncryptor module NullSerializer #:nodoc: def self.load(value) value end def self.dump(value) value end end class InvalidMessage < StandardError; end OpenSSLCipherError = OpenSSL::Cipher::CipherError def initialize(secret, *signature_key_or_options) options = signature_key_or_options.extract_options! sign_secret = signature_key_or_options.first @secret = secret @sign_secret = sign_secret @cipher = options[:cipher] || 'aes-256-cbc' @verifier = MessageVerifier.new(@sign_secret || @secret, digest: options[:digest] || 'SHA1', serializer: NullSerializer) @serializer = options[:serializer] || Marshal end def encrypt_and_sign(value) verifier.generate(_encrypt(value)) end def decrypt_and_verify(value) _decrypt(verifier.verify(value)) end def _encrypt(value) cipher = new_cipher cipher.encrypt cipher.key = @secret # Rely on OpenSSL for the initialization vector iv = cipher.random_iv encrypted_data = cipher.update(@serializer.dump(value)) encrypted_data << cipher.final "#{::Base64.strict_encode64 encrypted_data}--#{::Base64.strict_encode64 iv}" end def _decrypt(encrypted_message) cipher = new_cipher encrypted_data, iv = encrypted_message.split("--".freeze).map {|v| ::Base64.strict_decode64(v)} cipher.decrypt cipher.key = @secret cipher.iv = iv decrypted_data = cipher.update(encrypted_data) decrypted_data << cipher.final @serializer.load(decrypted_data) rescue OpenSSLCipherError, TypeError, ArgumentError raise InvalidMessage end def new_cipher OpenSSL::Cipher.new(@cipher) end def verifier @verifier end end #key generate encrypted_cookie_salt = 'encrypted cookie' encrypted_signed_cookie_salt = 'signed encrypted cookie' def key_generator secret_key_base = 'db1c366b854c235f98fc3dd356ad6be8dd388f82ad1ddf14dcad9397ddfdb759b4a9fb33385f695f2cc335041eed0fae74eb669c9fb0c40cafdb118d881215a9' key_generator = KeyGenerator.new(secret_key_base, iterations: 1000) CachingKeyGenerator.new(key_generator) end # encrypt secret = key_generator.generate_key(encrypted_cookie_salt || '') sign_secret = key_generator.generate_key(encrypted_signed_cookie_salt || '') encryptor = MessageEncryptor.new(secret, sign_secret, digest: 'SHA1', serializer: MessageEncryptor::NullSerializer) value = "{\"session_id\":\"6022d05887d2ab9c1bad8a87cf8fb949\",\"_csrf_token\":\"OPv/LxbiA5dUjVsbG4EllSS9cca630WOHQcMtPxSQUE=\"}" encrypted_message = encryptor.encrypt_and_sign(value) #encrypted_message = encryptor._encrypt(value) p '-----------encrypted value-------------' p encrypted_message # decrypt encrypted_message = 'bDhIQncxc2k0Rm9QS0VBT0hWc3M4b2xoSnJDdkZNc1B0bGQ2YUhhRXl6SU1oa2c5cTNENWhmR0ZUWC9zN05mamhEYkFJREJLaDQ3SnM3NVNEbFF3ZVdiaFd5YXdlblM5SmZja0R4TE9JbDNmOVlENHhOVFlnamNVS2g1a05LY0FYV3BmUmRPRWtVNUdxYTJVbG5VVUlRPT0tLXd1akRqOU1lTTVneU9LTWszY0I5bFE9PQ==--b0a57266c00e76e0c7d9d855b25d24b242154070' p '-----------decypted value-------------' puts encryptor.decrypt_and_verify encrypted_message p '---------------------------------------' 이 과정을 자바로 구현한 소스는 생략 깃헙에 올려두었습니다. 이 코드를 이용해서 서블릿 세션과 연동하는 방법은 추후 사측(?)과 협의되는 대로 공유할 예정입니다. 물론, 그 전에 쿠키를 공유할 필요가 없어지면(or 공유할 쿠키가 없어지면) 더 좋겠죠 :D
조회수 772

[인터뷰] 임팩트 베이스캠프 7기 | 디자인씽킹 B조

대중교통을 타고 이동할 때도, 집에서 밥을 먹을 때도 프로젝트를 고민하며 숨가쁘게 달려오고 있는 임팩트 베이스캠프 7기! DT프로젝트 팀별 인터뷰 세 번째 조를 만나보았습니다.권수연, 박소은, 엄석준, 이승연, 홍예진 베이스캠퍼가 속해있는 B조는 누구에게 공감하고, 어떤 사회문제를 해결하고자 하는지 볼까요?INTERVIEW .Q1. 하나의 키워드로 본인에 대해 소개해주세요!▲ 왼쪽부터 시계방향으로 권수연 님, 박소은 님, 엄석준 님, 홍예진 님, 이승연 님수연: “Arise, Shine” 나다움을 찾고자 하는 사람이에요. ‘교육’을 통해 다른 사람도 본연의 모습으로 살아갈 수 있도록 올바르게 세워주는 것이 제 비전입니다.소은: “작은 변화로 큰 변화를 이끄는 것” 작은 포인트를 교정하면 변화를 이끌어 낼 수 있다고 생각해요. 그 작은 포인트를 찾아내는 사람이 되고 싶습니다.석준: “대기만성형 인간” 지금은 스스로 어느정도 그릇을 채워가고 있는 단계라고 보는데요. 늦었다고 느껴질지 몰라도 완성되면 알찬 나를 기대해요.승연: “순간”이요. 지금 이 순간이 가장 젊을 때이고 결국 시간은 지나가고 있기 때문에 프로젝트 팀 혹은 가족, 지인과 함께 있을 때 그 자체에 집중하려고 노력하는 사람이에요.예진: “하고싶은 것 하고 살자” 제가 추구하는 모토에요. 내가 진짜 하고 싶은 걸 해 나가며 채워가는 것이 후회없는 삶이라고 생각해요.Q2. DT 프로젝트 문제정의의 발전(혹은 공감) 과정이 궁금해요▲ 프로젝트 주제 선정을 위해 논의 중인 B조의 모습예진: ‘장애인의 체육활동 증진’이 저희 팀의 첫 주제였는데요. 의미가 있을 것 같아서 선정하긴 했지만 다섯 명 모두 관심이 없던 분야라 공감 자체가 낮은 상태에서 시작했어요. 팀원의 지인을 통해 20대 시각장애인을 인터뷰하게 되었는데 그 과정에서 우리 팀이 더 공감할 수 있도록 대상을 구체화하여 시각장애인 문제를 다루기로 했어요.소은: 시각장애인이 겪는 불편함은 스포츠 활동 외에도 참 많더라고요. 인터뷰를 통해 우리가 생각지도 못한 문제가 있었다는 걸 인식하게 되었어요. 시각장애인의 생활 속 불편이 무엇인지에 대해 고민하고 ‘진짜’ 문제를 찾아가는 중이에요.수연: 저는 평소에 ‘교육’이라는 키워드에 몰입되어 있었기 때문에 개개인이 가진 잠재력을 들춰내는 변화에 초점을 맞추고 있었거든요. 그런데 프로젝트로 해결하고자 하는 문제는, 불편함을 바꿔주는 변화인거죠. 변화의 종류에 대해 알아가고 있는 중이에요.Q3. ‘시각장애인의 생활 속 불편함’에 주목한 B조, 어떤 프로토타입을 제작했나요?승연: [시각장애인은 공중화장실의 성별을 쉽게 구분하기 어렵다]는 불편함에 공감하고, 빠르게 프로토타입을 만들어 보았는데요. 인터뷰를 통해 시각장애인이 지하철 공중 화장실에서 성별을 구별하기 위해서는 점자를 만져봐야 한다는 것을 알게 되었어요. 그 점자 위치를 찾으려고 화장실 앞에서 헤매는 과정이 민망하지 않을까 생각했고, 점자가 아닌 유도블록으로 성별을 구분할 수 있도록 프로토타입을 제작하게 되었습니다.예진: 수수깡으로 미니 유도블록을 만들었다가 찰흙으로 실제 크기에 해당하는 프로토타입을 또제작했는데요. 현장 테스트 결과, 시각장애인 분들은 실제로 후각과 청각을 사용해서 구별하고 계셨어요. 여성 분들의 향수 냄새 혹은 구두 소리, 목소리 등을 통해서요!석준: 또 다른 프로토타입 중 하나는 [시각장애인은 식사를 할 때 반찬의 위치를 찾는 것이 어렵다]는 문제에 공감하여 만들었는데 아직 현장 테스트 전 단계이며, 인터뷰 섭외 중입니다.Q4. 이제 절반이 넘는 시간을 달려오셨는데, 팀으로 프로젝트를 진행해오며 느낀 점은 무엇인가요?소은: 저는 경영학과이기 때문에 팀플 경험이 많은데 보통 다수의 의견과 제 생각이 다르면 입을 열지 않았거든요. 그런데 DT 프로젝트 팀은 개인의 생각을 모두 존중해주고 오픈마인드로 서로의 이야기를 들어주는 것 같아요. 문제정의 같은 경우도 팀원 중 한 사람이 공감이 안되면 왜 공감이 안되는지 들어주고 함께 고민해줘요. 서로에게 자유롭게 생각을 말할 수 있는 이야기의 장이 열려 있다고 해야 할까요?수연: 저는 보이지 않는 가치를 발견하게 되었다는 점이 정말 좋아요. 또 ‘실패해도 된다’는 것을 알려주는게 디자인씽킹이라고 생각해요. 배움을 즐기고 교육자가 되고 싶은 학생으로서, 인사이트를 얻고 실행하는 이 모든 과정이 성찰의 습관을 만들어 주는 것 같아요. 또 저는 지금 ‘완벽하지 않은 나를 수용하는 훈련’을 하고 있다고 말씀드리고 싶어요.승연: 저도 실패해도 괜찮다는 말을 담아 두려고 노력하는 중인데요. 저는 완성된 상태에서 사람들에게 보여주고자 하는 강박 때문에 실패에 대한 두려움이 굉장히 크거든요. 또 저는 축산식품공학을 공부하고 있어서 과 특성상 팀플이 거의 없거든요. 각자의 역할을 ‘분업’하여 진행했던 팀플만 경험해보았는데 DT 프로젝트를 통해 ‘협업’에 대한 새로운 경험을 하고 있어요.예진: 이전에 팀 내에 공감하는 사람이 있으면 좋고 아니면 어쩔 수 없다는 주의였는데 공감의 중요성을 깨닫고 있는 중이에요. 공감하는 방법이 개념화되어 있는게 디자인씽킹이라고 생각하는데 저한테는 굉장한 센세이션이었어요. ‘공감을 이렇게 활용할 수 있구나’를 알게 되었습니다.Q5. 덧붙여서 IBC 인터뷰 단골질문을 여쭤볼게요! DT수업과 SL수업의 차이점은 무엇이라고 생각하시나요?수연: 우선 두 수업 모두 ‘Learning by doing’이라는 공통점을 가지고 있다고 생각해요. 차이점은 SL 수업이 나를 곤두세우면서 경험하게 한다면 DT 수업은 팀원끼리 서로의 온기를 느끼며 경험하게 한다는 것이에요. 비유를 들어보면 SL 수업은 나를 비춰보는 거울이고, DT 수업은 다른 사람 속에 내가 들어가 있는지(공감하고 있는지) 보는 활동인 것 같아요. 둘 다 정말 잘하고 싶어요.석준: 저는 두 수업 자체를 분리하는게 부자연스럽다고 생각하지만 SL 수업은 어두운 곳에서 무언가를 찾아가는 느낌이라면 DT 수업은 어느정도 조성된 안전지대에서 프로젝트를 하는 느낌이에요. 또 SL 수업에서 배운 것들을 직접 몸으로 부딪치면서 배우는 것이 DT 수업이라고 생각합니다. 예진: 저는 ‘감성과 이성’이라고 간단 명료하게 설명할 수 있을 것 같아요.Q6. 임팩트 베이스캠프의 모든 과정을 마친 후, 기대하는 것은 무엇인가요?소은: 사회를 위해서 무언가 하길 원하는 IBC 베이스캠퍼들과 지속적인 커뮤니티를 이어가길 원해요. 비단 비슷한 커리어를 갖게 되는 것만을 의미하는 게 아니라, 각자 다양한 자리에서 사회문제를 고민하고 해결할 때 서로 독려해주는 관계가 되었으면 하는 기대가 있습니다.수연: 항상 최상의 환경과 컨디션에서 프로젝트를 진행해야 된다고 생각했는데, 완벽하지 않아도 우리가 팀원으로 함께 할 수 있다는 것을 누리는 사람이 되었으면 좋겠어요.석준: 수업 초반에 제 DT 프로젝트 목표는 뚜렷한 아웃풋이 있어야 한다는 것이었어요. 평소에도 ‘결과물’이 중요하다고 생각하는 사람이었는데 그러다 보니 ‘과정’에서 배우는 것을 소홀히 했던 것 같아요. 그런데 이제는 결과에 크게 연연하지 않고, 어떤 프로젝트에 참여하더라도 과정을 통해 배운 나만의 무기를 갖추는 것이 목표에요.▲ 눈오는 날, 특별한 단체사진을 남기게 된 B조시각장애인이 일상생활에서 겪는 불편함을 느껴보고 공감하고자 집에서 불을 꺼둔 채 생활해보는 노력까지 마다하지 않는 B조. 프로젝트의 결과를 떠나 진심으로 배움을 즐기고 있는 베이스 캠퍼들의 모습이 참 아름답습니다. 우리의 배움과 채움이 더 나은 세상을 위한 나눔으로 이어지길 기대합니다. 다음 인터뷰로 돌아오겠습니다 :)#루트임팩트 #헤이그라운드 #임팩트베이스캠프 #디자인씽킹 #체인지메이커 #전략적리더십 #소셜벤처 #사회공헌
조회수 1329

에이스프로젝트 리더십토론

에이스프로젝트는 함께 고민하면서 다양한 방안을 찾는 토론 제도가 많은데요. 앞서 얘기했던 운영위원회, 타운홀 미팅, 말하는 로댕 등이 대표적인 사례입니다.자세한 내용은 [에이스문화] 메뉴에 있답니다 :)이것 말고도 또 있는데요! 바로 ‘리더십 토론’입니다. ‘리더십 토론’은 말 그대로 리더들이 모여서 토론을 하는 문화인데요. 모든 리더가 다 같이 모여서 더 나은 근무환경이나 조직문화를 만들기 위한 논의를 하기도 하기도 하지만 주로 세분화된 리딩 역할 별*로 모여 리더십 토론을 진행합니다.*에이스프로젝트에는 어떤 역할이 있을까? https://blog.naver.com/aceproject/221120418503팀에는 팀 디렉터, 팀 매니저가 있고프로젝트에는 PD, 일정을 관리하는 스크럼 마스터가 있는데요.각 역할끼리 모여서 리더십 토론을 해요!팀 디렉터만 모여서 토론을 하는 날도 있고, PD와 스크럼 마스터가 함께 모여서 얘기하는 날도 있지요.각 역할별로 해당되는 이슈가 있을 때마다 비정기적으로 열려요.  리더십 토론에서는 리더들이 각자 역할을 더 잘 수행하기 위한 노하우를 공유합니다.리딩을 하면서 생긴 고민을 함께 나누고 해결 방법을 모색합니다. 역할에 맞는 리딩을 하기 위한 좋은 방법이 무엇인지, 어떤 부분을 개선하고 발전시켜야 하는지, 그동안 놓친 부분은 없는지 등에 대해 논의하면서 지속적으로 전문성을 업그레이드하는 자리라고 볼 수 있습니다.모두가 알 수 있게 안내도 해요!지금까지 역할별로 다양한 주제들과 함께 했습니다. 평가 방식, 면담 노하우도 공유하고요. 팀원의 일과 삶의 균형을 위해서 더 나은 일 하는 방식에 대해서도 함께 얘기해 보았어요.그동한 했던 많은 토론주제들!이번 리더십 토론은 팀 매니저와 함께 조직문화 키워드 설문 조사에 대한 리뷰였습니다. 리더십 토론은 한 시간 정도 진행되며 격렬한 논쟁과 토론이 벌어지죠. 매우 진지. 엄근진.리더십 토론이 끝나고 나면 회의록은 전사 공유 되어 리더십 토론에 들어오지 않았던 사람들도 내용을 알 수 있고 피드백도 언제든 줄 수 있습니다!
조회수 1195

영어공부 꾸준히 하는 법

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

개발자의 경력관리란?

경력이 아닌 업력이 되는 단계에 이르러야 가능한 것 아닌가 합니다.대부분의 경력은 '어느 회사의 누구'라는 표현에서 만들어진 것이 아닙니다.진정한 경력의 결과는 '자신의 이름'이 곧 브랜드화 되는 것입니다.매우 당연하게,하루 이틀, 한 두해 한다고 해서 얻어지는 것이 아닙니다."10년 경력!"10년 이상 한 분야나 하나의 도메인, 하나의 테크, 하나의 경력, 하나의 경험을 꾸준하게 파고들었을 때에 얻어지고, 그러는 경험속에서 인사이트, 통찰력이 생기게 됩니다.물론. 그래서, 20대에도 명성을 얻을 수 있는 '경력관리'가 가능하다고 이야기합니다.(실제 얻은 사람을 많이 봤습니다. 그들은 10대에 시작했죠. )회사의 테두리 내에서 얻을 수 있는 '경력'은 '경험'일뿐입니다.자신의 이름을 중심으로 기술할 수 있을 때에 '경력'이라고 이야기할 수 있습니다.개발자라면...글을 써서도 얻을 수 있고,강연을 해서도 얻을 수 있고,GitHub에 오픈소스를 공개하면서도 얻을 수 있습니다.현재 30대와 그 이전의 개발자라면...10대와 20대도 똑같습니다.40대, 50대 이후를 준비하세요.반복적인 일, 똑같은 일, 회사의 프로세스의 하나인 일만 하는 '사람'이라면...그냥, 그 회사의 톱니바퀴가 되는 것입니다.대부분 '경력관리'가 잘 안됩니다.앞으로 50대 이후에도 '브랜드'를 얻을 사람이 되려면...자신의 '경력'관리를 잘 해야 얻을 수 있습니다.나중에 닭 튀기거나 치킨 배달할 것이 아니라면...관리를 잘해야 합니다.경력관리가 가능하려면 어떤 회사를 찾아야 할까요.다음을 기억하세요.1. 구루급 개발자가 있는 회사를 찾으세요.2. 자신이 주도적으로 무언가를 만들 수 있는 권한과 책임을 줄 수 있는 회사를 찾으세요.3. 커뮤니티나 외부 강연, 외부 오픈소스 개발 행사에 적극 참여할 수 있는 기회를 주는 회사를 찾으세요.4. 반복적인 업무와 정체된 마켓에서만 반복적으로 서비스를 하는 회사는 회피하세요.5. 우리 도메인은 원래 이래, 이 일은 원래 이래... 이런 식으로 이야기하는 '상급자'가 있는 회사를 피하세요.6. 쉽게 설명할 수 있도록 준비하고, 리뷰를 할 수 있는 기회와 시간이 주어지는 회사를 찾으세요.그리고, 마지막으로...비전은 누가 주거나 만들어 주지 않습니다.결국, 자기 자신이 찾아야 하는데...이것도, 주변에 이야기가 통하는 '구루급 개발자'가 있어야 그나마 방향성을 찾기 좋습니다.혼자 고민하거나,주변에 비슷한 사람들끼리 고민해봐야 답이 안 나옵니다.꼭, 기억하세요!'구루급 개발자'와 상의하세요.그분들은 실패와 성공, 포기와 단념, 선택과 집중에 대해서 알고 있답니다.퇴근시간이라면..구루급 개발자에게 치맥 한잔 하자고 하세요!

기업문화 엿볼 때, 더팀스

로그인

/