스토리 홈

인터뷰

피드

뉴스

조회수 888

좀 독특하지만 나쁘지 않은 사람들에 대하여(ft.취향)

주변 분들과 얘기하다보니 가끔 넘치는 독특함을 주체하지 못해 갑분싸 메이커가 되는 경우나 입이 근질거려 죽겠는데 말할 사람이 없어서 그냥 평범함에 봉인되어 살고 있는 분들이 종종 있었어요. 요즘엔 개인의 취향과 독특함을 많이 인정해주는 분위기이긴 하지만, 그럼에도 뭔가 독특한 사람의 생각과 행동, 발언에 대해 '평범한 프레임'을 씌우는 건 쉽사리 사라지지 않아요.갑분싸..이런 분들을 바라보는 외부의 시선은 세 가지 정도가 있어요.1우선은 "신기함"이 있어요. 예를 들어 고수를 진짜 좋아하는거야. 그 쌀국수에 넣어먹는 초록색 향기핵폭탄 말이예요. 토끼처럼 오물오물 고수를 씹어먹는 사람을 보면, 마치 잊혀진 세계에 존재하는 미지의 생물을 보는 듯한 신기함이 들기도 해요. 뭐. 처음봐? 풀먹는거2다음은 "뭐야 왜 저래 이상해 무서워.." 가 있어요. 예를 들면 너무 이과감성이 넘치는 거예요. 폭탄제조에 엄청난 관심이 있어. 아니면 저처럼 생물학에 관심이 많아서 바이러스의 감염과정을 보면서 감탄하고 막 그래. 뒷주머니에 뉴튼 과학잡지 꽂고 다닐것같고 집에 샬레나 플라스크같은 게 있을 것 같은 부류에요.  물론 여기에는 애니덕후도 있을거예요. 에반게리온의 세계관을 꿰고 다닌다거나 아키라나 공각기동대, 인랑의 디스토피아적 세계에 심취한 분들을 보면 사람들은 왜 저래 무서워...하면서 힐끔힐끔하기도 해요. (전 좋아해요.)뭐..뭐지...테러리스트신가..3마지막은 "넌 틀렸어.." 가 있어요. 특히 결혼얘기나 출산, 페미니즘, 정치적 이슈 등등 사회적으로 양분되어 있거나 과도기에 있는 이슈들에게서 많이 발생해요. 사람은 당연히 어느 한쪽의 입장을 지닐 수 있어요. 근데 반대쪽 입장에 있는 분들이 그걸 틀렸다고 해요. 그래서 결혼안하고 애를 안낳으면 인생의 중요한 기쁨을 잃어버린 것이라고 혼날 때도 있어요. 과연 그게 혼날 일일까요...?갑자기 절 훈육.. 이러한 반응들을 받으며 살 수 있지만, 명확한 건 그 사람들이 나쁘진 않아요. 그냥 하나의 생각을 지니고 있는 거고 그게 꽤나 나름대로 잘 정립되어 있는 것 뿐이예요. 또는 좋아하는 것이 명확하고 깊이 알고 있는 것 뿐이죠. 물론 가끔 아집이나 상대방을 공격하는 수단이 된다거나, 나쁜 생각으로 지구를 멸망시키고 싶은 분들도 있을 수 있어요. 그런 사람들은 나빠요. 생각은 존중받아 마땅하지만 행동은 책임이 따라요. 타노스가 했던 생각은 맬서스도 똑같이 했어요. 킹스맨의 발렌타인도 똑같이 했어요. 사실 무수한 사람이 비슷한 생각을 할 지도 몰라요. 생각하는 건 자유에요. 하지만 손가락을 튕겨 그걸 실천하는 것은 다른 문제죠. 그걸 책임질 수 있어야 해요. 타노스가 아니라면 행동을 조심해서 해야해요.오늘은 그런 이상한 취향을 지닌 사람들을 한 번 알아보려고 해요.1. 막 이상한 음악 좋아해.: 영화OST나 epic 장르처럼 웅장하고 홈스피커가 비싸야 제맛인 그런 음악을 좋아하는 분들, 인디/제3세계/우울하기 그지없는 음악/피아노곡/뉴에이지 덕후인 분들이 있어요. 네 저예요. 음악취향은 어디가서 쉽게 말하기 어려워요. 내 플레이리스트를 공개하는건 뭔가 부끄러운 일이죠. 링딩동도 좋아하고 클래식도 좋아하거든요. 잔혹한 천사의 테제도 좋아하고 원피스OP곡도 가지고 다녀요. 음악을 다양하게 듣는건 다양한 자극을 처리할 수 있다는 좋은 능력이예요.전 한스짐머 콘서트갔을 때 미치게 좋았는데..2. 양자역학 같은 거 좋아해.문이과 상관없이 이런 분들이 있어요. 블랙홀이나 양자역학, 초끈이론, 다중우주, 평행세계, 범죄심리학, 전쟁사, 기호학, 신화학, 연금술(?) 등등 인문/자연과학에 심취한 분들도 계세요. 좋은거에요. 세상을 굉장히 색다르고 놀라운 시각으로 볼 수 있어요. 가끔 너무 심취하면 모든 게 무상해서 현타가 올 때도 있으니 현타를 조심해야해요.3. 자본주의 싫어정확히는 싫다라기 보단 그 폐해에 대해서 고민하시는 분들이예요. 그래서 분산경제나 공유경제, 수정자본주의, 대체자본주의 등등에 대해 목소리를 높여요. 이런 얘기는 전세계의 유명한 석학들도 목소리를 내는 것들이예요. 이건 이상한게 아니죠. 이런 분들이 세상을 바꾸는 거예요. 괜찮아요. 저도 자본주의는 문제가 많다고 생각해요. 이런 분들은 특히 EBS다큐프라임 매니아인 경우가 있어요.4. 맥주는 김에 먹어야 해.음식의 정확한 궁합을 중요하게 생각하는 분도 있어요. 혀는 모두 제각각의 수용체를 지니고 있어요. 사람마다 다르죠. 당연히 좋아하는 음식도 달라요. 맥주는 김, 소주는 마요네즈, 와인에 삼겹살을 좋아할 수도 있어요. 그럼 그렇게 먹으면 되는거에요. 맥주집을 갔는데 김이 없으면 편의점가서 자기 걸 그냥 사오면 돼요. 민폐가 아니예요. 이상하게 보지 않아도 됩니다.5. 열정맨이야.사람은 살아가면서 삶의 태도라는 걸 만들어요. 관조적이거나, 염세적이거나, 적극적이거나, 공격적이거나 등등... 열정이 넘쳐서 뭐든 시도하고 덤벼들고 다 잘될거라고 낙관을 얘기하는 분들도 있어요. 물론 저와는 결이 좀 맞진 않지만 그 사람이 틀리진 않았어요. 그 분의 삶의 태도는 그런거예요. 그리고 그런 태도로 지금까지 전혀 문제없이 잘 살아왔잖아요? 그럼 된 거에요.6. 그래비티를 막 8번씩 재관람해...또 볼거다!!제 얘기예요. 전 그래비티를 무려 8번을 봤어요. 2D로, 3D로, IMAX 3D로, 4DX로, 스크린엑스로, 친구랑, 혼자, 애인이랑 등등..... 심지어 이번에 아이맥스 레이저로 재개봉한대요. 또 볼 거예요. 뭔가 한가지에 꽂혀서 파고드는 분들이 있어요. 그럴 수 있어요. 카레에 미쳐서 2,3년 내내 하루 한끼는 반드시 카레만 먹는 사람도 있고, 나루토 극장판을 10번씩 다시 돌려보는 사람도 있어요. 좋아하는 무언가가 있다는 건 좋은거에요. 무언가에 에너지를 집중할 줄 안다는 얘기이기도 하거든요. 오히려 없는 게 더 슬픈거 아닌가용?7. 말이 많고 막 나대.그렇죠. 나댈 수 있어요. 어색한 분위기를 싫어해서 분위기를 띄우려고 노력하는 걸 수도 있고 원래 그냥 성향이 그럴수도 있어요. 그 사람 입에서 싸구려 유우머 같은 내용이나 젠더감수성이 0에 수렴하는 헛소리가 나오는 게 아니라면 말많은 사람이 딱히 틀린 건 아니예요. 생존전략같은거죠. 어떤 사람은 침묵으로, 어떤 사람은 수려한 용모로, 어떤 사람은 갑빠로...각자 생존전략을 가지고 살아가요. 말 많은 사람은 영화 속 모건 프리먼 옆에 붙어다니는 말많은 파트너 형사같은 캐릭터로 생존전략을 잡은 거예요. 8. 나 혼자 밥을 먹고..나 혼자 영활보고... 뚜두 뚜두우...혼자 뭘 하는 사람들이 너무 많아진 지금 사실 이건 특별할 건 아니에요. 하지만 그럼에도 혼자????그걸???? 이라는 프레임이 있는 몇몇 요소들이 있어요. - 콘서트 혼자간다. 아니 집중해서 보고싶으면 그럴 수 있지. - 패밀리레스토랑도 혼자갈 수 있어요. 투움바 파스타가 땡길 수도 있잖아요. 돈 많으면 혼자 가는거지. - 놀이공원 혼자간다. 갈 수 있지. 혼자서 추억을 곱씹으며 티익스프레스의 짜릿함에 내 몸을 내맡기는 건 잘못이 아니예요.9. 패션감각의 한계를 깼어그래도 이쁘시잖아!?그럴 수 있죠. 패션. 전 그냥 집에서 갓 나온 파자마느낌의 헐렁하고 아무 프린팅도 되어있지 않은 그런 옷 좋아해요. 누가보면 전원주택에 정원가꾸려고 나오신 60대 할아버지의 실내복같은 느낌일 수도 있어요. 린넨이나 면소재 좋아하거든요. 패션은 나를 표현하는 아주 직관적인 요소예요. 특히 색과 다양한 소재, 위 아래의 매칭, 머리 염색과 악세서리 등 그렇게 나를 드러내는 거죠. 그게 뭐 틀렸다 어쨋다 할 게 있나요. 핑크바지를 입을 수도 있는거지. 그게 나의 시력에 악영향을 준다거나 그러지 않아요. 핑크색은 안정감을 주기까지 하니까요.10. 자유한국당을 좋아해.조..좋아할 수도 있........(위험하다!!! 위험해!!!)그렇죠..뭐 어느 시대나 진보와 보수는 존재했고, 중도당도 있었고... 병자호란 때 최명길과 김상헌도 그렇게 파이팅넘치게 설전을 벌였어요. 늘 두 개의 다른 의견과 세 개의 견제기구가 존재하면서 서로의 독점과 부패를 막기위해 나름의 노력을 했죠. 지금의 정치체계는 그렇게 탄생했어요. 물론 그 본래의 의미와는 좀 많이 달라진 느낌이 있긴 하지만...(나 이러다 개털리는 거 아니겠지?...저의 정치색은 비밀입니다..근데 저긴 아니야..)뭐 좋아하는 걸 틀렸다고 할 순 없을 것 같아요. (하지만 나에게 강요는 놉놉....)다만 정치색은 투표라는 행동을 통해 결과를 만들게 된다는 특징이 있어요. 그리고 그 결과는 많은 사람들에게 영향을 미치죠. 그러니 시민으로써 현명한 가치관을 지녀야 해요.마무리에 핵폭탄을 써놓고 글을 정리하려고 해요. 원래 위험할까봐 저런 건 안쓰려고했는데... 뭐 틀린 얘기도 아니고 사실 취향과 선택에서 정치사회적인 부분을 얘길 안할 수 없거든요. 맷데이먼씨도 JTBC나와서 마음껏 자신의 정치관에 대해 펼치신 걸 보면 어쩌면 모두가 자유롭게 자신의 가치관을 나누고 존중할 수 있는 사회를 만드는 게 더 중요한 것 같아요.모두가 모두를 미워하거나 두려워하지 않는 세상이 왔으면 좋겠어요. 다들 소중한 하루하루를 통해 자신의 삶을 채워나가고 있으니까요. 취향과 가치관이란 건 그런 소중한 시간들의 총합아닐까요. 나름의 생각을 가지고 삶을 살아가는 분들을 존중하고 응원해주는 게 맞다고 생각해요. 그리고 우리도 그렇게 살아야하구요.참고로 전 양자역학이나 신화, 기호학, 괴물 이야기, 세계사, 전쟁사, 면역학, 우주얘기 등등을 짱좋아해서 뉴튼잡지를 뒤적거리고 혼자 즐거워하고 그런답니다..끗
조회수 1845

인턴의 시선에서 본 스타트업 문화

나는 캣니스!나는 워낙 빠르게 돌아가는 스타트업 ‘어니스트펀드'에서 생존해보고자 헝거게임의 여전사처럼 어니스트펀드의 여전사를 꿈꾸는 UX 팀 인턴 ‘캣니스'이다. 2개월 동안 보고 느낀 어니스트펀드의 스타트업 문화 두 가지 ‘수평적인 소통’과 ‘자유로운 근무환경' 대해 이야기하고자 한다.1. 스타트업 수평적인 소통은 이름부터“안녕하세요. 포세이돈이에요.”“반가워요. 머니입니다."“저는 시나몬이에요.”“안녕하세요. 저는 캣니스입니다. 잘 부탁드립니다.”위의 대화를 보면 마치 인터넷상에서 이루어지는 채팅이 연상되기도 한다. 하지만 이 대화는 내가 처음 어니스트펀드에 와서 팀원들과 나눴던 인사다.어니스트펀드의 인턴 면접을 볼 때 부대표님이 자신을 “제우스” 라고 소개하였다. ‘제우스?! 내가 알고 있는 그리스 로마 신화에 나오는 신들의 왕 제우스란 말인가…’ 하며 매우 당혹스러우면서 지금까지 봐왔던 면접 중 굉장히 유쾌했던 기억이 있다.협업 툴 ‘Slack’에 있는 팀원 네임대게 회사들은 일반적으로 이름과 직급으로 서로를 부른다.("김xx 대리님", "유과장님" 등). 이 자체만으로 서로간에 주는 직급의 위계질서가 생기고 수직적인 관계가 형성된다. 따라서 많은 스타트업은 수평적인 조직 문화를 만들기 위해 영어 이름을 사용하기도 한다.어니스트펀드도 수평적인 문화를 만들기 위해 영어 이름을 쓰지만 조금 더 특별한 닉네임을 쓴다. 나는 이런 닉네임 형태가 해당하는 사람의 직위와 이름을 합쳐 만들어 낸 어니스트펀드 안에만 존재하는 하나의 캐릭터라는 이미지가 더 강하게 박힌다. 그래서인지 팀원들과 이야기를 할 때 수평적인 소통을 하기에 조금 더 편하다고 실제로 느낀다.사실 나는 인턴으로 온 지 첫 주 동안 닉네임에 가까운 이름을 부르면 예의가 없어 보일 것 같은 마음으로 팀원들에게 닉네임과 ‘-님' 자를 붙여 불렀다. (예를 들면, “머니 님, 점심 드셨어요?”) 그런데 나와 함께 UX업무를 하시는 ‘테일러'는 나에게 “내 안에 위계질서를 만들지 말아요.”라고 조언을 해주셨다. 나도 모르게 수평적인 조직 안에서 위계질서를 만들고 있지는 않았을까 하고 아차 싶었다.21. 수평적인 소통과 수직적인 의사결정을 지향합니다.(어니스트펀드 매뉴얼 21번)스타트업에서 수평적인 문화를 만드는 가장 큰 이유는 모든 사람의 의견을 듣기 위해서다. 그리고 구성원 모두가 이해하고 동의한 상태에서 일을 진행하는게 목표 지점에 도달하기가 더 효과적이기 때문이다. 그렇기 때문에 영어 닉네임과 같은 방식을 팀원들과 자유로운 커뮤니케이션의 수단으로 이용된다.2. 쉴 수 있는 자유와 근무환경출근한 지 이튿날, 회사원들이 가장 졸린 오후 2시에 잠을 깨기 위해 커피를 마시러 아고라(Agora_각종 음료가 있는 휴식 겸 소통의 공간)로 갔다. 내 눈앞에는 생각지도 못한 상황이 펼쳐져 있었고 신선한 문화 충격을 받았다.당시 아고라 앞에 위치한 전면 유리로 구성된 미팅룸 안에는 대표님과 외부 손님이 미팅 중이었고, 그 맞은편 소파에는 대놓고 드러누워 자는 ‘터보’가 보였다.도대체 이게 무슨 일이란 말인가????미팅 중인 외부 손님 바로 앞에서 드러누워 자는 직원, 그런 모습이 아무렇지 않은 양 평온한 상태로 미팅을 진행 중인 대표의 태도는 이해하려야 이해할 수 없는 장면이었다.순간 이 장면을 본 나는 ‘미팅룸 안에 설치된 블라인드를 어떻게 내리지?’, ‘자는 터보를 깨워야 하나?’ 등의 이 상황을 어떻게 대처해야 할지에 대한 생각들로 어쩔 줄 몰랐다. 하지만 그 시각 아고라에 커피를 마시러 온 팀원은 아무 일이 없다는 듯 커피를 타서 자리로 돌아갔고, 이 회사 공간 안에서 나는 마치 다른 나라 사람이 된듯 한 기분이 들었다.어니스트펀드의 agora어니스트펀드 인턴으로 오기 전까지 1년 동안 평균 연령 40세인 사람들로 구성된 보수적인 회사에 있던 나에게는 생각지도 못할 일이었다. 업무 중 잠이 쏟아질 때면 화장실 변기 위에서 15분간 쪽잠을 자고, 아무렇지 않은 표정으로 돌아와 업무로 복귀하던 나였다. 이런 상황은 나뿐만 아니라 대부분 회사원이 겪었을 일상이라고 생각한다.하지만 어니스트펀드의 일상은 달랐다. 언제 어디서나 업무 중에 과열된 머리를 식힐 수 있는 자유가 있다. 최대의 업무 효율을 내기 위해 서로의 눈치를 보지 않고 휴식을 취할 수 있는 권리가 보장되어 있다는 것이다. 또한 그 권리를 구현할 수 있는 근무환경이 조성되어 있다.손님이 와도 굴하지 않고 잘 수 있는 우리 팀원들이 멋있어요.위의 말은 서상훈 대표가 지난 워크숍에서 팀원들에게 했던 말이다. 회사 안에서 어떤 상황과 요건으로 구애받지 않고 팀원 스스로가 업무의 효율성을 높이기 위해 적합한 환경으로 만들어 나가는 것에 대한 만족감이 아닐까 싶다.일이 잘 안풀릴때는 여의도 전경을 보며 휴식을!“직원들이 자신의 생각을 자유롭게 표현할 수 있고,낡은 규칙은 임의로 깨뜨릴 수 있으며,자신이 일하는 공간을 자기 집처럼 사랑할 수 있어야 한다.”-IDEO CEO 톰 켈리-스타트업하면 빠지지 않는 키워드 중 하나는 자유로운 근무환경이다. 근무환경은 문화를 만들고 직원들의 업무 생산성을 높이는 데 기여할 것이다. 자유로운 공간 안에서 더 좋은 시너지를 내기 위해서는 팀원들이 공간 그대로를 200% 활용할 수 있는 태도와 자세가 관건이라고 생각한다.분명 스타트업에서 팀원들과 수평적인 소통을 하기 위해 풀어나가는 방식과 자유로운 근무 환경이 장점만 가지고 있는 것은 아니라고 생각한다. 이것들이 긍정적으로 이루어지려면 팀원 간의 믿음이 먼저 바탕에 깔려있어야 한다. 내가 인턴으로서 바라본 어니스트펀드는 활기 넘치는 근무환경을 바탕으로 한 믿음이 있었기에 더욱 매력적인 곳이었다. 앞으로 어니스트펀드의 젊은 에너지가 핀테크의 기폭제로 되기를 기대해 본다.#어니스트펀드 #인턴 #기업문화 #스타트업 #스타트업문화 #조직문화 #사내문화 #인턴인터뷰 #인사이트 #경험공유 #팀원 #팀문화 #팀워크 #팀플레이
조회수 1443

고객사의 든든한 물류 컨설턴트, 품고 사업개발실 영업팀장 은진님_Interview

  1. 안녕하세요! 은진님:) 간단한 자기소개 부탁드립니다! 안녕하세요. 품고에서 영업 팀장을 맡고 있는 고은진입니다!      2. 은진님이 품고에 입사하게 된 계기는 무엇일까요?  저는 두손컴퍼니가 가진 미션에 대한 공감이 컸던 것 같아요. 또 두손컴퍼니의 비즈니스 모델 자체가 비즈니스가 성공하면 소셜 미션은 함께 달성되는 구조인 것도 마음에 들었어요.    대학교 때부터 인액터스라는 사회 공헌 비즈니스 동아리에서 활동했어요. 취약계층분들을 위한 비즈니스 모델을 개발하여 운영하는 동아리였고 그때 두손컴퍼니를 처음 알게 되었어요.      당시 북한 이탈 주민 취업 연계 및 인식 개선 위한 북한 음식 관련하여 창업하였었는데 비즈니스를 키우고 있다는 느낌보다는 봉사한다는 느낌이 강했어요.    그때 제가 비즈니스를 통한 소셜임팩트를 창출하는 것에도 관심이 많지만, 저 스스로의 성장도 중요시한다는 것을 느꼈고 당시 품고 풀필먼트 비즈니스 영업 담당자로 일하는 것이 저의 성장과 소셜 임팩트를 함께 낼 수 있는 경험이 될 것 같아 느껴 지원하게 되었어요.     3. 품고, 영업 매니저는 어떤 일을 하는 사람일까요?       품고 영업 매니저는 두손컴퍼니의 연 계약 서비스인 품고의 신규 계약을 진행하고 두손컴퍼니의 매출과 성장 동력을 만드는 곳이에요.     구체적으로는 품고 서비스를 문의하는 화주사들의 전화나 메일에 대해 응대를 하고 그중에서 미팅을 원하는 화주사 분들과 미팅을 진행하고 있습니다. 또 품고 서비스와 잘 맞을 것 같은 고객사는 먼저 미팅을 제안하고 있어요.    미팅을 통해서는 고객사와 품고 모두에 이익이 되는 방향을 제안드리고, 계약 이후에는 물류팀에 고객사를 인계하고 물류 매니저 분들과 협업하여 제품 입고 현황 및 CS 이슈 등을 정리하여 정기 물류 보고서를 발행하거나 현업과 고객사 사이에서 품고 서비스 물류 관련 이슈를 조정하기도 합니다.     4. 일을 하다보면 기쁜일만 있는 것은 아닐텐데 혹시 영업팀에서 일하며 겪게되는 힘든 점은 어떤 것이 있을까요? 고객사와 현업 매니저분들과의 물류 관련된 이슈가 있을 시 중간에서 문제를 해결해야하는 경우가 많은데 서로의 입장을 모두 알기 때문에 어떤 해결책을 내야할 지 어려울 때가 많은 것 같아요.   예를들어, 우리는 프로세스에 맞춰줄 의향도 있었고 상대에 대한 이해도도 높았다고 생각하여 파트너로서 함께하고 싶었던 고객사가 있었어요.    하지만 우리의 생각과는 다르게 고객사가 우리를 파트너로 대우하지 않거나, 품고의 프로세스를 무시한 채 무리한 요구를 해오는 경우가 있었고, 그럴때마다 우리 또한 파트너로서 상대를 존중하는 태도를 견지하지 못한다는 생각이 들때마다 조금 힘들다는 생각이 들었어요.     5. 품고 영업 팀장으로 일하면서 가장 많은 성장을 할 수 있게 해준 경험은 무엇일까요?  우선 두손컴퍼니는 권한과 책임이 자유로운 회사에요. 결과에 대한 책임이라기 보단 과정을 온전히 스스로 컨트롤 해볼 수 있는 분위기라 누구라도 열정만 있다면 성장하기 굉장히 좋은 회사라고 생각해요.   작년부터 품고 마케팅을 시작하면서 고객사 문의가 굉장히 많이 늘었고 영업팀 미팅도 따라서 많이 늘었어요. 미팅을 통해 다양한 고객사를 만나고 경험해보면서 스스로 많이 성장했다고 생각해요.   또 많은 미팅을 나가면서 힘들기도 했지만 제가 하는 업무를 통해 계약이 진행되고 품고의 매출도 140% 정도 성장한 것을 보니 보람을 느꼈던 것 같아요.   특히 디자이너 핸드백 및 악세서리를 판매하고 계신 마르헨제이 고객사분들 같은 경우 이전 물류 센터에서 품고 물류 센터로 이전을 하게 되시면서 이전 자체가 쉽지는 않은 부분들이 많았어요.    이 때 고객사 분께 이전 물류 센터의 연락처를 받아 직접 커뮤니케이션을 진행하면서 이전을 도와드렸던 경험이 있는데 당시 저 또한 어려운 물류 이전을 도우면서 배웠던 부분이 많았고 고객사 담당자 분께서도 감사하다는 말씀을 전해주셔서 좋았던 것 같아요.     6. 요즘 영업팀에서 가장 우선순위로 진행하고 계신 업무는 무엇이고 신입 매니저분은 어떤 일을 하게 되실까요?  새로운 분이 오기 전 신입 매니저분들의 업무 가이드가 되어줄 매뉴얼 작성을 가장 우선적인 작업으로 생각하고 있어요.  매뉴얼은 신입 매니저분들이 이전에 영업팀에서 겪었던 어려움이나 실수들을 반복하지 않도록 돕고 영업 역량을 더 키울 수 있는 기반 자료로 활용 될 예정입니다.    또한, 매뉴얼이 가이드 역할 외에도 이후 들어오시는 신입 매니저분들의 인사이트를 지속적으로 쌓을 수 있는 기록 자산이 되기를 기대하고 있습니다.   신입 매니저분의 경우 매뉴얼을 바탕으로 처음에는 서비스 소개서 없이도 서비스를 잘 소개할 수 있을 만큼 서비스에 대한 이해도를 높이는 것부터 시작하여 인바운드  화주사 미팅,계약 고객사 관리,계약 이후 관련 이슈 컨트롤 등의 업무와 품고의 수익률을 개선하는 업무 등을 맡게 되실거에요.     7. 앞으로  은진님이 하고 싶은 일은 무엇인가요? 품고의 고객사를 더 많이 늘려 정말 규모면에서 크게 성장하고 전국의 거점도시에 품고 센터를 만드는 일에 생기는 기여하고 싶어요. 그리고 품고의 성장을 통해 더 많은 채용이 발생했으면 좋겠고 제가 하는 일을 통해 두손컴퍼니의 미션이 달성된다면 기쁠 것 같아요.   영업팀장으로 일하며 품고 안에서 물류와 연관된 새로운 서비스들을 기획하고 고객사들에게 제공하며 품고의 매출과 규모를 키워보고 싶습니다.   입사 초에는 품고에서 많은 경험을 쌓은 뒤 물류 경험을 살려서 아마존을 가거나 공공 정책을 세우고 대기업의 CSR 프로젝트를 컨설팅해주는 일을 해보고 싶었어요.입사한지 1년 정도가 지난 지금은 공공정책 관련 일을 해보는 것에 더 끌리고 있는 것 같아요.   정말 큰 단위의 공공정책 프로젝트를 런칭해서 실질적이고 더 큰 소셜임팩트를 창출하는 일을 해보고 싶다는 생각이 강해졌어요.     8. 앞으로 함께 일하게 되실 품고 영업 팀원분께 하고 싶은 한 마디!   두손컴퍼니의 우리가 가지고 있는 물류 관련 퍼즐들이 무엇인지 정확히 파악할 줄 알아야 해요. 그리고 그것들을 잘 활용하여 고객사와 품고에 모두에게 더 나은 프로세스를 컨설팅해줄 수 있어야 하기 때문에, 고객사의 물류 현황을 파악하기 위한 정확한 분석력과 현재 가진 재료를 잘 활용하여 최선의 결과를 만들 수 있는 응용력이 뛰어난 분이었으면 좋겠어요.     예를 들어, 내가 팀장이라면 나의 의견에 도전하고 더 나은 제안을 할 수 있을 만큼 주도적이고 하고 싶은 업무나 새로운 것을 도전하는 사람을 볼때 영업팀장으로서 열심히 지원해주고 싶을 것 같아요.   때문에, 단순하게 영업을 친절하게 서비스를 소개하고 실적만 올리는 것이라고 생각하시는 분은 지원하지 않았으면 좋겠습니다. 주도적으로 고객사에게 물류 컨설팅을 제안하고 물류 고민을 해소시켜줄 수 있는 도전 정신을 가진 분이면 좋을 것 같아요.    마지막으로는 혹시나 저희가 물류 회사다 보니 몇 가지 걱정이 되실수도 있을 것 같아 말씀드리자면 현재 두손컴퍼니는 여직원분들이 유급 보건 휴가를 눈치 보지 않고 갈 수 있는 복지 제도가 마련되어 있고 현업 물류 매니저분들도 마찬가지겠지만 물류 회사라고 영업팀이 거친 일을 하지는 않기 때문에 그런 부분은 걱정 안 하셨으면 좋겠습니다:) 
조회수 1023

정확함을 만들어내는 사람들, 품고 생산 관리 매니저 현지님의 이야기.

   1. 안녕하세요! 현지님:) 간단한 자기소개 부탁드립니다! 안녕하세요. 품고 입고팀 생산 관리 매니저 김현지입니다:)   2. 현지님이 품고에 입사하기게 된 계기는 무엇일까요? 앞으로 이커머스 시장 규모는 지속적으로 커지고 그 중에서도 스타트업의 비중이 늘어날 것이라는 건 이제 부정할 수 없는 흐름인 것 같아요. 때문에 물동량이 아직 많지 않거나 브랜딩이 중요한 스타트업들에게 적합한 물류서비스에 대한 니즈가 더욱 커질 것이라 생각했어요.   저는 이후에 두손컴퍼니에서 물류에 대해 제대로 배우고 난뒤에는 개발도상국에서 풀필먼트 기업을 창업해보고 싶은 마음도 있어요. 두손컴퍼니는 풀필먼트 서비스를 통해 이커머스 시장을 이롭게 한다는 비즈니스 미션 외에도 일자리 창출이라는 소셜 미션을 가지고 있잖아요? 개발도상국도 앞으로 이커머스 시장이 커질 것이라 생각하고 좋은 물류서비스를 만들어 많은 사람들을 고용할 수 있는  풀필먼트 기업을 창업해보는 것이 꿈이에요:)   3. 품고, 생산 관리 매니저는 어떤 일을 하는 사람인가요?      파트너사의 제품이 최종적으로 출고가 가능한 상태가 되도록 생산 관리 업무를 담당하고 있어요. 취미생활 브랜드인 하비풀의 제품 같은 경우는 부자재가 다양하고 반제조 상태의 제품을 완제품 상태로 만들어 출고 가능한 상태로 만들어야 해요. 출고 직전 제품의 마지막을 책임지는 팀입니다. 다양한 종류의 고객사 제품을 어떤 프로세스로 생산을 진행해야 더 빠르고 효율적일지 고민하고 개선해나가고 있어요.   영업팀분들과 상의하여 새로 계약 된 파트너사 제품의 임가공 여부를 먼저 파악하고, 생산 관리가 필요한 제품이라면 품고 센터 입고 이후 생산 스케줄을 관리하는 일을 해요. 그리고 미팅을 통해 제품을 직접보고 필요한 생산관리를 파악한 후 가장 효율적인 생산 관리 프로세스를 파트너사에 제안하고 협의하는 일을 하고 있습니다.      4. 임가공을 하며 힘든 점은 무엇인가요? 아무래도 임가공에서의 문제로 오배송이 났을 때가 가장 힘든 것 같아요. 하지만 최대한 침착하게 어떤 부분에서 문제가 났는지 추적하려고 노력하고 있습니다. 그 이후에는 생산 관리 프로세스에서 개선할 여지가 있는지 파악하고 꾸준히 인사이트를 적용해나가고 있죠.   5. 품고 생산 관리 매니저로 일하면서 가장 많은 성장을 할 수 있게 해준 경험은 무엇일까요? 아기들을 위한 피크닉백 브랜드 플레이젤로를 만들고 계신 코니밤니니의 경우 출고 전 생산 관리가 필요한 부분이 많아 처음 들어올 때부터 생산 관리 매니저가 미팅을 통해 프로세스를 컨설팅해드린 경우에 속해요. 그때 당시 아직 회사에 입사한지 얼마 안되어 운영실 부실장이신 재영님과 함께 미팅에 들어갔었고 많은 것을 배울 수 있는 기회가 되었던 것 같아요.   생산 관리 미팅을 통해서는 어떤 프로세스가 필요하고 그에 따르는 시간과 인력이 얼마나 필요한지 컨설팅해드려요. 원자재 관리 b2b와 b2c 출고에 따라 임가공 작업이 달라지는 부분에 대해서도 체크하고 프로세스에 적용했죠.   예를 들면 원자재 관리할 때 부피가 큰 제품의 경우 더 빠르고 정확하게 임가공 작업을 할 수 있도록 로케이션 및 보관 위치를 협의하고 완제품이 안된 제품과 각종 부자재, 안전재고의 보관 방법에 대해 기획해요. 파트너서와의 미팅 이후에는 실제 작업을 해주실 팀원분들과 커뮤니케이션을 통해 프로세스 마지막으로 협의합니다.   OPP 같은 경우 사이즈가 작업에 효율적이지 않을 경우에 작업을 더 효율적으로 하기 위해 부자재를 제안드리기도 하고 고객사의 담당자 분과 함께 작업 프로세스를 진행해보며 견적 및 프로세스를 지속적으로 의논하여 개선해나가고 있습니다.  이커머스 제품은 브랜드마다 형태가 다양하고 그에 따른 생산 관리 프로세스가 모두 달라져야하는 부분이 많아 영업 담당자 및 고객사 커뮤니케이션을 통해 각 고객사 제품별로 이해도를 높이는 것이 중요한 것 같아요.   6. 요즘 생산 관리 프로세스에 가장 많이 신경을 쓰고 있는 브랜드가 있을까요? 늘 모든 파트너사 제품들의 생산 관리 프로세스에 대해 고민하고 개선해나가고 있지만 굳이 뽑자면 요즘은 ‘달바’라는 화장품 브랜드를 만들고계신  비모뉴먼트 제품에 좀 더 신경을 쓰고 있어요. 면세점 건은 라벨이 붙여서 나가야 하는데 면세점마다 라벨링이 다르고 안팍의 라벨링도 모두 달라 다른 제품들 보다 훨씬 더 많은 신경을 써주어야 해요. 달바 화장품 같은 경우 생산 관리는 물론 출고팀과의 협업을 해야하는 부분도 많아 커뮤니케이션에도 신경쓰고 있고요. 라벨링이 다양하게 작업되어야 할 경우 배송지에 따라 라벨을 별도로 관리하고 작업 시에도 수량과 종류를 정확하게 팀원분들께 전달드리고 있습니다.      7. 앞으로 두손컴퍼니에서 현지님이 하고 싶은 일은 무엇인가요? 임가공 작업에 필요한 프로세스를 지속적으로 개선해보고 싶어요. 지금 하고 있는 임가공 프로세스 중 더 효율적으로 진행할 수 있는 방법이 있는 단계들은 무엇이 있을지 고민하고 개선해서 더 높은 수준의 생산 관리가 필요한 제품이 들어와도 문제없이 제품관리를 도와드리고 싶고 현재의 생산 관리 퍼포먼스를 더 올려보고 싶어요. 궁극적으로는 원활한 생산 관리를 통해 파트너사분들의 제품이 앞으로 더 많이 판매되었으면 좋겠어요!      8. 앞으로 함께 일하게 되실 품고의 새로운 생산 관리 팀원분께 하고 싶은 한 마디!  품고의 생산 관리 매니저는 정확함을 만드는 사람이라고 생각해요. 정확하게 일을 할줄 아는 사람이라는 뜻도 있겠지만 어떤 생산 관리 작업도 정확하게 이루어질 수 있는 프로세스를 만드는 사람이라는 뜻에 더 가까워요.   다양한 제품들을 만나기 때문에 생산 관리 프로세스를 기획하는 일이 매번 다르게 다가올 때가 많고 어렵게 느껴질 때가 있지만 늘 고민하면 답은 나오더라구요. 저와 함께 품고 ‘생산 관리의 정확함’을 만들어가실 분들은 많이 지원해주세요!:)
조회수 2112

블로그 운영 방법에서 엿보는 VCNC의 개발문화

VCNC에서 엔지니어링 블로그를 시작하고 벌써 새로운 해를 맞이하였습니다. 그동안 여러 글을 통해 VCNC 개발팀의 이야기를 들려드렸습니다. 이번에는 엔지니어링 블로그 자체를 주제로 글을 적어보고자 합니다. 저희는 워드프레스나 텀블러와 같은 일반적인 블로깅 도구나 서비스를 사용하지 않고 조금은 개발자스럽다고 할 수 있는 특이한 방법으로 엔지니어링 블로그를 운영하고 있습니다. 이 글에서는 VCNC 개발팀이 엔지니어링 블로그를 운영하기 위해 이용하는 방법들을 소개하고자 합니다. 그리고 블로그를 운영하기 위해 방법을 다루는 중간중간에 개발팀의 문화와 일하는 방식들에 대해서도 간략하게나마 이야기해보고자 합니다.블로그에 사용하는 기술들Jekyll: Jekyll은 블로그에 특화된 정적 사이트 생성기입니다. GitHub의 Co-founder 중 한 명인 Tom Preston-Werner가 만들었으며 Ruby로 작성되어 있습니다. Markdown을 이용하여 글을 작성하면 Liquid 템플릿 엔진을 통해 정적인 HTML 파일들을 만들어 줍니다. VCNC 엔지니어링 블로그는 워드프레스같은 블로깅 도구를 사용하지 않고 Jekyll을 사용하고 있습니다.Bootstrap: 블로그 테마는 트위터에서 만든 프론트엔드 프레임워크인 Bootstrap을 이용하여 직접 작성되었습니다. Bootstrap에서 제공하는 다양한 기능들을 가져다 써서 블로그를 쉽게 만들기 위해 이용하였습니다. 덕분에 큰 공을 들이지 않고도 Responsive Web Design을 적용할 수 있었습니다.S3: S3는 AWS에서 제공되는 클라우드 스토리지 서비스로서 높은 가용성을 보장합니다. 일반적으로 파일을 저장하는 데 사용되지만, 정적인 HTML을 업로드하여 사이트를 호스팅하는데 사용할 수도 있습니다. 아마존의 CTO인 Werner Vogels 또한 자신의 블로그를 S3에서 호스팅하고 있습니다. VCNC Engineering Blog도 Jekyll로 만들어진 HTML 파일들을 아마존의 S3에 업로드 하여 운영됩니다. 일단 S3에 올려두면 운영적인 부분에 대한 부담이 많이 사라지기 때문에 S3에 올리기로 하였습니다.CloudFront: 브라우저에서 웹페이지가 보이는 속도를 빠르게 하려고 아마존의 CDN서비스인 CloudFront를 이용합니다. CDN을 이용하면 HTML파일들이 전 세계 곳곳에 있는 Edge 서버에 캐싱 되어 방문자들이 가장 가까운 Edge를 통해 사이트를 로딩하도록 할 수 있습니다. 특히 CloudFront에 한국 Edge가 생긴 이후에는 한국에서의 응답속도가 매우 좋아졌습니다.s3cmd: s3cmd는 S3를 위한 커맨드 라인 도구입니다. 파일들을 업로드하거나 다운로드 받는 등 S3를 위해 다양한 명령어를 제공합니다. 저희는 블로그 글을 s3로 업로드하여 배포하기 위해 s3cmd를 사용합니다. 배포 스크립트를 실행하는 것만으로 s3업로드와 CloudFront invalidation이 자동으로 이루어지므로 배포 비용을 크게 줄일 수 있었습니다.htmlcompressor: 정적 파일들이나 블로그 글 페이지들을 s3에 배포할 때에는 whitespace 등을 제거하기 위해 htmlcompressor를 사용합니다. 또한 Google Closure Compiler를 이용하여 javascript의 길이도 줄이고 있습니다. 실제로 서버가 내려줘야 할 데이터의 크기가 줄어들게 되므로 로딩속도를 조금 더 빠르게 할 수 있습니다.블로그 관리 방법앞서 소개해 드린 기술들 외에도 블로그 글을 관리하기 위해 다소 독특한 방법을 사용합니다. 개발팀의 여러 팀원이 블로그에 올릴 주제를 결정하고 서로의 의견을 교환하기 위해 여러 가지 도구를 이용하는데 이를 소개하고자 합니다. 이 도구들은 개발팀이 일할 때에도 활용되고 있습니다.글감 관리를 위해 JIRA를 사용하다.JIRA는 Atlassian에서 만든 이슈 관리 및 프로젝트 관리 도구입니다. VCNC 개발팀에서는 비트윈과 관련된 다양한 프로젝트들의 이슈 관리를 위해 JIRA를 적극적으로 활용하고 있습니다. 제품에 대한 요구사항이 생기면 일단 백로그에 넣어 두고, 3주에 한 번씩 있는 스프린트 회의에서 요구사항에 대한 우선순위를 결정합니다. 그 후 개발자가 직접 개발 기간을 산정한 후에, 스프린트에 포함할지를 결정합니다. 이렇게 개발팀이 개발에 집중할 수 있는 환경을 가질 수 있도록 하며, 제품의 전체적인 방향성을 잃지 않고 모두가 같은 방향을 향해 달릴 수 있도록 하고 있습니다.VCNC 개발팀이 스프린트에 등록된 이슈를 얼마나 빨리 해결해 나가고 있는지 보여주는 JIRA의 차트.조금만 생각해보시면 어느 부분이 스프린트의 시작이고 어느 부분이 끝 부분인지 아실 수 있습니다.위와 같은 프로젝트 관리를 위한 일반적인 용도 외에도 엔지니어링 블로그 글 관리를 위해 JIRA를 사용하고 있습니다. JIRA에 엔지니어링 블로그 글감을 위한 프로젝트를 만들어 두고 블로그 글에 대한 아이디어가 생각나면 이슈로 등록할 수 있게 하고 있습니다. 누구나 글감 이슈를 등록할 수 있으며 필요한 경우에는 다른 사람에게 글감 이슈를 할당할 수도 있습니다. 일단 글감이 등록되면 엔지니어링 블로그에 쓰면 좋을지 어떤 내용이 포함되면 좋을지 댓글을 통해 토론하기도 합니다. 글을 작성하기 시작하면 해당 이슈를 진행 중으로 바꾸고, 리뷰 후, 글이 발행되면 이슈를 해결한 것으로 표시하는 식으로 JIRA를 이용합니다. 누구나 글감을 제안할 수 있게 하고, 이에 대해 팀원들과 토론을 하여 더 좋은 글을 쓸 수 있도록 돕기 위해 JIRA를 활용하고 있습니다.JIRA에 등록된 블로그 글 주제들 중 아직 쓰여지지 않은 것들을 보여주는 이슈들.아직 제안 단계인 것도 있지만, 많은 주제들이 블로그 글로 발행되길 기다리고 있습니다.글 리뷰를 위해 Pull-request를 이용하다.Stash는 Attlassian에서 만든 Git저장소 관리 도구입니다. GitHub Enterprise와 유사한 기능들을 제공합니다. Jekyll로 블로그를 운영하는 경우 이미지를 제외한 대부분 콘텐츠는 평문(Plain text)으로 관리 할 수 있게 됩니다. 따라서 VCNC 개발팀이 가장 자주 사용하는 도구 중 하나인 Git을 이용하면 별다른 시스템의 도움 없이도 모든 변경 내역과 누가 변경을 했는지 이력을 완벽하게 보존할 수 있습니다. 저희는 이런 이유로 Git을 이용하여 작성된 글에 대한 변경 이력을 관리하고 있습니다.또한 Stash에서는 GitHub와 같은 Pull request 기능을 제공합니다. Pull request는 자신이 작성한 코드를 다른 사람에게 리뷰하고 메인 브랜치에 머지해 달라고 요청할 수 있는 기능입니다. 저희는 Pull request를 활용하여 상호간 코드 리뷰를 하고 있습니다. 코드 리뷰를 통해 실수를 줄이고 개발자 간 의견 교환을 통해 더 좋은 코드를 작성하며 서로 간 코드에 대해 더 잘 이해하도록 노력하고 있습니다. 새로운 개발자가 코드를 상세히 모른다 해도 좀 더 적극적으로 코드를 짤 수 있고, 업무에 더 빨리 적응하는데에도 도움이 됩니다.어떤 블로그 글에 대해 리뷰를 하면서 코멘트로 의견을 교환하고 있습니다.코드 리뷰 또한 비슷한 방법을 통해 이루어지고 있습니다.업무상 코드 리뷰 뿐만 아니라 새로운 블로그 글을 리뷰하기 위해 Pull request를 활용하고 있습니다. 어떤 개발자가 글을 작성하기 위해서 가장 먼저 하는 것은 블로그를 관리하는 Git 리포지터리에서 새로운 브랜치를 따는 것입니다. 해당 브랜치에서 글을 작성하고 작성한 후에는 새로운 글 내용을 push한 후 master 브랜치로 Pull request를 날립니다. 이때 리뷰어로 등록된 사람과 그 외 개발자들은 내용에 대한 의견이나 첨삭을 댓글로 달 수 있습니다. 충분한 리뷰를 통해 발행이 확정된 글은 블로그 관리자에 의해 master 브랜치에 머지 되고 비로소 발행 준비가 끝납니다.스크립트를 통한 블로그 글 발행 자동화와 보안준비가 끝난 새로운 블로그 글을 발행하기 위해서는 일련의 작업이 필요합니다. Jekyll을 이용해 정적 파일들을 만든 후, htmlcompressor 통해 정적 파일들을 압축해야 합니다. 이렇게 압축된 정적 파일들을 S3에 업로드 하고, CloudFront에 Invalidation 요청을 날리고, 구글 웹 마스터 도구에 핑을 날립니다. 이런 과정들을 s3cmd와 Rakefile을 이용하여 스크립트를 실행하는 것만으로 자동으로 이루어지도록 하였습니다. VCNC 개발팀은 여러 가지 업무 들을 자동화시키기 위해 노력하고 있습니다.또한, s3에 사용하는 AWS Credential은 IAM을 이용하여 블로그를 호스팅하는 s3 버킷과 CloudFront에 대한 접근 권한만 있는 키를 발급하여 사용하고 있습니다. 비트윈은 특히 커플들이 사용하는 서비스라 보안에 민감합니다. 실제 비트윈을 개발하는데에도 보안에 많은 신경을 쓰고 있으며, 이런 점은 엔지니어링 블로그 운영하는데에도 묻어나오고 있습니다.맺음말VCNC 개발팀은 엔지니어링 블로그를 관리하고 운영하기 위해 다소 독특한 방법을 사용합니다. 이 방법은 개발팀이 일하는 방법과 문화에서 큰 영향을 받았습니다. JIRA를 통한 이슈 관리 및 스프린트, Pull request를 이용한 상호간 코드 리뷰 등은 이제 VCNC 개발팀의 문화에 녹아들어 가장 효율적으로 일할 수 있는 방법이 되었습니다. 개발팀을 꾸려나가면서 여러가지 시행 착오를 겪어 왔지만, 시행 착오에 대한 반성과 여러가지 개선 시도를 통해 계속해서 더 좋은 방법을 찾아나가며 지금과 같은 개발 문화가 만들어졌습니다. 그동안 그래 왔듯이 앞으로 더 많은 개선을 통해 꾸준히 좋은 방법을 찾아 나갈 것입니다.네 그렇습니다. 결론은 저희와 함께 고민하면서 더 좋은 개발문화를 만들어나갈 개발자를 구하고 있다는 것입니다.저희는 언제나 타다 및 비트윈 서비스를 함께 만들며 기술적인 문제를 함께 풀어나갈 능력있는 개발자를 모시고 있습니다. 언제든 부담없이 [email protected]로 이메일을 주시기 바랍니다!
조회수 2430

같은 크기가 달라보이는 이유, 시각적 보정 이해하기

여기 크기를 맞춘 도형 조합 A, B가 있습니다. A, B 중 사각형과 원의 크기 비율이 같아 보이는 조합은 무엇인가요?  저는 B조합이 훨씬 더 자연스럽게 보입니다. A는 가로 세로 크기를 똑같이 맞췄으며, B는 상대적으로 면적을 고려해 원형의 크기를 사각형보다 조금 더 크게 그렸습니다. 이처럼 사람의 눈에 자연스럽게 보이도록 조정하는 작업을 ‘시각적 보정’이라고 합니다. 디자이너, 혹은 디자이너가 아닌 사람들도 다양한 프로그램을 통해 미세한 크기를 똑같이 맞출 수 있습니다. 하지만 프로그램이 오브젝트를 인식하는 것과 사람이 보는 것은 다르기 때문에, 때론 아주 정확한 것이 부자연스럽게 보일 수 있습니다. 서로 다른 형태 사이의 차이점을 보완해주는 작업이 필요합니다.  최근 저는 이러한 시각적 보정에 대해 요목조목 잘 정리된 루크 존스(Luke Jones)의 “Optical Adjustment”를 읽었습니다. 여기에 몇 가지 추가 사례를 덧붙여 함께 소개합니다. (“Optical Adjustment”의 원문 번역글은 강수영님의 “시각적인 보정”에서 확인할 수 있습니다.)1. 도형에 따른 크기 조정하기앞서 살펴본 원과 사각형의 크기 조절부터 다시 볼까요? 사방 80pixel의 영역 안에서 사각형은 원보다 넓은 면적을 차지합니다. 우리 눈은 사방 길이를 통해 크기를 인식하기 보다는, 면적을 보고 어림잡아 비슷한 크기를 가늠합니다. 사각형보다 원의 크기를 조금 더 크게 그려주면 비교적 두 도형의 크기가 동일해 보입니다.2. 시각적 무게 중심 고려하기시각적 무게 중심에 따른 정렬은 플레이 버튼 아이콘을 통해서 해볼 수 있습니다. 원형과 삼각형을 중앙 정렬하면 A 아이콘처럼 됩니다. 중앙에서 빗겨나 있는 것처럼 보이는데요, 이는 삼각형의 무게 중심이 원형의 중심과 맞지 않아서 그렇습니다. 이렇게 서로 다른 형태의 오브젝트를 정렬할 때는 무게 중심을 고려하여 B 아이콘처럼 수정해주는 것이 좋습니다.3. 면적 대비 색상 조정하기면적에 따라서 색상의 무게감이 달라집니다. A는 파란 아이콘에 비해 텍스트 컬러가 살짝 연해 보입니다. 이렇게 넓은 면적과 비교적 좁은 면적(텍스트/라인)에 같은 색상이 쓰이는 경우가 많습니다. 이럴 때 좁은 면적의 컬러를 조금 더 짙게 수정해주면 면적의 넓이와 상관없이 (비교적) 동일한 색상으로 인지됩니다.3. 형태를 고려해 오브젝트 정렬하기이번에는 슬로워크에서 디자인한 DMZ국제다큐영화제 시그니처를 예시로 정렬을 살펴보겠습니다. 자세히 보면 시그니처의 우측 가장자리에 ‘~제' 로 끝나는 첫줄과 ‘-29.’로 끝나는 마지막줄이 있습니다. 온점은 한글보다 공백을 많이 포함하고 있습니다. 그래서 A처럼 정직하게 정렬하면 마지막줄만 움푹 들어간 것 처럼 보입니다. 이를 B처럼 튀어나오게 수정해주는 것이 보기에 자연스럽습니다.  4. 명도에 따라 굵기 조정하기4번의 컬러 조정과 같은 맥락으로, 오브젝트의 명도에 따라 굵기가 달리 보일 수 있습니다. 좌측의 흰색 텍스트와 우측 상단 검은색 텍스트(굵기 조정 전)는 같은 굵기의 폰트입니다. 검은색 텍스트가 상대적으로 가늘어 보여서 조금 더 굵게 수정했습니다. 네거티브, 포지티브 적용을 동시에 할 때 이런 점을 고려하곤 합니다.5. 영문폰트와 한글폰트 조합시 조정하기한글폰트와 영문폰트를 조합해서 디자인하는 경우가 많습니다. 편집디자인 툴인 인디자인 프로그램에는 ‘합성글꼴’이라는 기능이 있어 숫자, 영문, 국문, 기호 등을 각각 다른 폰트로 지정하고 세세하게 크기도 다르게 할 수 있습니다. 서로 다른 폰트를 억지로 이어붙이는 것이기 때문에, 크기값이 같아도 한글폰트가 더 커보입니다.(좌측 텍스트) 이때 크기와 높낮이를 직접 조정해주는 것이 좋습니다.(우측 텍스트)6. 커닝(글자 간격 조정)하기왼쪽 텍스트를 자세히 들여다보면 글자의 각기 다른 모양 때문에 배열이 균등하지 않아 보입니다. 이때 글자의 형태를 고려해 적당한 간격으로 보이도록 수정하는 것을 커닝(kerning)이라고 합니다. 커닝은 상대적으로 공백을 많이 가진 글자(숫자 1, 알파벳 A, W, V)일수록 조정을 필요로 합니다. 디자인을 전공하면 가장 기초적으로 배우는 부분임에도, 저는 커닝을 완벽히 하는 것이 제일 어렵습니다.커닝을 연습할 수 있는 사이트도 있습니다. 완성도에 따라 점수도 매겨줍니다. 간단하게 여러분의 눈썰미가 얼마나 날카로운지 확인해보세요. -> 커닝 해보기참고: Luke Jones - Optical Adjustment#슬로워크 #스티비 #디자인팀 #디자이너 #꿀팁
조회수 1064

자바스크립트 기초 문법 정리 Part 3

함수와 이벤트에 대한 내용이 이렇게 간략할지 몰라 따로 파트를 나누어 포스팅을 진행하였는데 불필요한 나눔이 되었네요. 하지만 곧 더 간략하고 직관적으로 볼 수 있도록 기초 문법 총 정리 포스팅을 하도록 하겠습니다. 혹여 참고 문서로 본 포스팅을 보시는 분들은 곧 올라오는 총정리 포스팅을 참고하시면 좋을 것 같습니다.함수function 함수명() {    실행문;    return 데이터;}참조 변수 = function() {    실행문;}function 함수명() {(매개 변수1, 매개 변수2)    실행문;}   이벤트<button id="btn" onclikc="alert('event!')">버튼></button>이벤트 종류onmouseover - 마우스가 지정한 요소에 올라갔을 때 발생.onmouseout - 마우스가 지정한 요소에 벗어났을 때 발생.onmousemove - 마우스가 지정한 요소를 클릭했을 때 발생.ondvlclick - 마우스가 지정한 요소를 연속 두 번 클릭했을 때 발생.onkeypress - 지정한 요소에서 키보드가 눌렸을 때 발생.onkeydown - 지정한 요소에서 키보드를 눌렀을 때 발생.onkeyup - 지정한 요소에서 키보드를 눌렀다 떼었을 때 발생.onfocus - 지정한 요소에 포커스가 갔을 때 발생.onblur - 지정한 요소에 포커스가 다른 요소로 이동되어 잃었을 때 발생.onchange - 지정한 요소의 하위 요소를 모두 로딩했을 때 발생.onunload - 문서를 닫거나 다른 문서로 이동했을 때 발생.onsubmit - 폼 요소에 전송 버튼을 눌렀을 때 발생.onreset - 폼 요소에 취소 버튼을 눌렀을 때 발생.onresize - 지정된 요소의 크기가 변경되었을 때 발생.onerror - 문서 객체가 로드되는 동안 문제가 발생되었을 때 발생.참고문헌:Do it! 자바스크립트+제이쿼리 입문 - 정인용JavaScript 튜토리얼 문서 (http://www.w3schools.com/js/default.asp)티스토리 블로그와 동시에 포스팅을 진행하고 있습니다.http://madeitwantit.tistory.com#트레바리 #개발자 #안드로이드 #앱개발 #Node.js #백엔드 #인사이트 #경험공유
조회수 908

마케터의 인생을 편하게 해줄 앱 키워드 성과 자동분석

키워드 성과 자동분석은 ‘원래 당연히 되는 기능 아님?’이라고 생각하실 수도 있지만 상황이 조금 달라졌습니다. 유저가 키워드 광고를 클릭하고 데스크탑 또는 모바일 홈페이지로 이동했다면 이 케이스는 ‘당연히’ 자동 분석이 됩니다. 그러나 키워드 광고를 클릭했는데 앱스토어 또는 앱 실행으로 연결된다면? 분석이 되게 만들 수는 있지만 ‘자동분석’은 불가능입니다.‘그 정도는 수작업으로 분석해도 괜찮겠네’라고 생각하시는 분들이 있을 것 같습니다. 분석 시스템 개발을 업으로 하는 저희 역시도 처음엔 그렇게 느꼈었으니 말이지요. 그러나 실무에서의 몇가지 케이스를 접하고 나서 완전히 잘못된 생각이었다는 것을 알게 되었습니다. 와이즈트래커가 키워드 성과 자동분석을 개발한 계기이기도 합니다. Unhappy Case 1 – 모빌리티 앱대리운전이나 카쉐어링 등의 모빌리티 분야는 불가피하게 앱을 통해야 제대로된 서비스를 이용할 수 있습니다. 스마트폰의 GPS를 이용해서 위치정보를 파악해야 하기 때문이죠. 상황이 이렇다 보니, 모바일에서 네이버 키워드 광고를 클릭하면 실제 서비스로 연결되지 않고 앱 설치를 권유하는 브릿지 페이지로 이동하는 경우가 많습니다. 이 광고의 KPI는 앱 설치와 앱에서의 전환이 되겠지요.문제는 각각의 키워드가 얼마만큼의 앱 설치를 만들어 내는지 자동분석이 되지 않는 다는 점입니다. 자동으로 안되니 수동으로 해야지요. 키워드마다 트래킹 URL을 입력하는 식으로 말입니다. 키워드가 100개 이내라면 할만 할 텐데, 이게 수백 개 단위가 되면 정말이지 혼자서는 감당을 못합니다. 차라리 인형 눈알을 붙이고 말지요. 그런데 그것이 실제로 일어났습니다.교양 있게 표현하면 Brute-force 알고리즘, 시쳇말로 노가다. 중간에 하나만 틀려도 폭망이다.우선 트래킹 URL을 600개 생성합니다. 이 URL을 키워드에 붙여넣고 저장하는 작업을 또 600번 합니다. 도합 1200번의 노가다 끝에 ‘다시는 이 미친 일을 하기 싫다’는 생각이 가장 처음 들었다고 합니다. 이런 말도 안되는 일을 피해갈 방법이 없을지 문의를 주셨고 와이즈트래커는 뚝딱뚝딱 기능을 개발했습니다. Unhappy Case 2 – 이커머스 앱검색어에 가장 민감한 분야가 이커머스일 것입니다. 기본적으로 상품의 개수만큼 키워드가 늘어납니다. 게다가 최근에는 ‘미세먼지 마스크 추천’이나 ‘가성비 좋은 발렌타인데이 선물’처럼 구문을 검색하는 경우가 늘고 있습니다. 이제는 구문 단위로 대응해야 해서 관리하는 키워드가 늘어날 수 밖에 없는 구조입니다. 키워드가 늘어나면 광고비도 비례해서 증가할 것입니다.이렇게 키워드 광고가 엄청나게 많다 보니, 광고를 통해 모바일웹으로 들어와서 상품만 살펴보고 실제 구매는 추가 할인을 받기 위해 앱에서 끝내는 유저도 있을 것 같습니다. 그런데 어떤 키워드가 유저를 앱으로 많이 이동시키는지 알 수 없다는 것이 현업에서의 고민이었죠. 이것만 알아낸다면 “키워드 광고 성과가 이렇게 높습니다. 저를 전적으로 믿으셔야 합니다.”라고 할 수 있는데 데이터가 없다는 것이 문제였습니다.‘앱에서 구매하면 할인’을 보고 웹에서 앱으로 넘어가는 경우, 얼마나 될까?이커머스 고객사에 키워드 자동분석을 적용한 결과는 아주 인상적이었습니다. 전체 앱 인스톨 중 약 7% 정도가 웹 광고를 통해 발생하고 있었으며, 이 중 80%는 검색 광고의 영향을 받는 것으로 나왔으니까요. 인스톨을 7% 정도 늘리기 위해서 증액해야 하는 광고비를 생각하면 결코 무시할 수 있는 수준이 아니라는 이야기. 게다가 이렇게 유입된 유저의 약 10%가 구매고객으로 전환했으니 그야말로 대박이었죠. 자동분석은 이렇게 동작해요내용은 꽤 단순합니다. 자동분석이기 때문이죠. 실무자가 할게 없습니다. 자동분석이니까요!1. 유저가 네이버에서 ‘마스크’를 검색했습니다. 파워링크에 광고들이 떠있는데요, 이 중에서 쿠팡을 클릭했습니다. 2. 키워드 광고를 클릭하니 쿠팡 모바일웹으로 연결 됐습니다. 화면 하단에 ‘앱 할인’ 배너가 있네요. 이걸 클릭합니다.2-1. 만약 ‘앱 할인’ 배너를 눌렀는데 단말기에 앱이 없는 상태라면? 앱을 설치할 수 있는 스토어로 넘어가게 되죠. 앱을 설치하고 실행합니다. 3. 앱을 실행하니 ‘마스크’ 화면이 나옵니다. 이제 상품들을 살펴보면 되겠네요. 정리하자면 [네이버에서 ‘마스크’ 키워드 광고 -> 모바일웹 -> 앱 설치]로 이어진 케이스입니다. 이 과정에서 1건의 앱 설치가 발생했지요. 마케터가 아무런 설정을 하지 않아도 와이즈트래커는 이 상황을 [‘마스크’ 키워드를 통한 1건의 앱 설치]로 ‘자동분석’합니다. 가만히 있어도 리포트에 데이터가 착착 쌓입니다. 우리가 만들었지만 신박하군요! 손발이 편안한 마케팅을 위하여마케팅 오토메이션 솔루션의 수준이 높아져서 그것이 대중화되면 분명 지금보다 손이 덜 가는 환경에서 실무를 진행할 수 있을 것입니다. 그때가 될 때 까지는 머리 속에서 행복회로를 굴리며 버티는 정신이 필요할지도 모르겠습니다.그렇다고 하더라도 수백개 키워드에 일일이 트래킹 URL을 박아 넣는 일은 지금이라도 사라져야 합니다. 위의 두가지 사례와 비슷한 문제가 있다면 와이즈트래커에 알려주세요!
조회수 7007

안드로이드 앱의 Persistent data를 제대로 암호화해 보자! (1/2)

들어가기오늘 소개해드릴 글은 안드로이드에서 좀 더 안전하게 파일 시스템에 데이터를 저장하는 방식에 관한 내용입니다. 이 글은 중급 이상, 상급 이하 안드로이드 개발자를 대상으로 작성했으며 완독하는데 약 20분 정도가 필요합니다. 최대한 쉽게 쓰려고 노력했습니다만 이 글이 잘 이해되지 않는 독자분들은 이 문서 말미의 더 보기 섹션에 링크된 외부 문서들을 읽어보시는 편이 좋습니다.1부에서는 Shared preferences 에 저장하는 데이터를 암호화 하는 방식에 대해 다루고 있으며, 2부에서는 데이터베이스를 암호화 하는 방식에 대해 다루겠습니다.내 앱의 데이터, 과연 유출로부터 안전할까?안드로이드 공식 사이트의 저장소 개발 가이드 문서는 데이터를 저장하는 여러 가지 방법을 소개하고 있습니다. 그 중 ‘내부 저장소’ 의 다음 특징은 눈여겨볼 만 합니다.기기의 내부 저장소에 파일을 직접 저장할 수 있습니다. 기본적으로, 내부 저장소에 저장된 파일은 해당 애플리케이션의 전용 파일이며 다른 애플리케이션(및 사용자)은 해당 파일에 액세스할 수 없습니다. 사용자가 애플리케이션을 제거하면 해당 캐시 파일은 제거됩니다.즉, 다른 애플리케이션에 노출하면 곤란한 중요한 정보들은 내부 저장소에 담아두면 안전하다고 할 수 있습니다. 하지만, 정말일까요? 다음 예제를 이용해 내부 저장소에 저장한 사용자의 중요한 정보를 어떻게 탈취하는지 알아보겠습니다. 예제 앱은 충성 사용자에게 보상하기 위해 사용자가 앱을 몇 번 실행시켰는지를 기록합니다.class AppRanTimesRecordingActivity : AppCompatActivity() {    privateval sharedPrefs by lazy {        // Shared preferences 는 Internal storage 에 저장된다.        getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE)    }    private var appRanCount = 0    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        accessToSharedPrefs()        appRanCount++        Toast.makeText(applicationContext, "App has ran $appRanCount times!!", Toast.LENGTH_LONG).show()        finish()    }    override fun onDestroy() {        saveSharedPrefs()        super.onDestroy()    }    private fun accessToSharedPrefs() {         sharedPrefs.run { appRanCount = getInt(KEY_APP_RAN_COUNT, 0) }    }    private fun saveSharedPrefs() {        sharedPrefs.edit().run({            putInt(KEY_APP_RAN_COUNT, appRanCount)            apply()        })    }    companion object {        private const val SHARED_PREF_NAME = "MySecureSettings"        private const val KEY_APP_RAN_COUNT = "appRanCount"    } } [리스트 1] MODE_PRIVATE 로 보호하는 SharedPreferences 사용앱의 데이터는 /data/data/com.securecompany.secureapp 에 저장되어 있습니다만, 앱을 release 모드로 빌드하면 adb 명령으로도 볼 수 없으니 안전하다고 할 수 있을 겁니다. 실제로 adb 명령을 이용해 저장한 파일을 보려고 시도하면 아래와 같은 오류가 발생합니다.$ adb shell "run-as com.securecompany.secureapp ls -al /data/data/com.securecompany.secureapp" run-as: Package 'com.securecompany.secureapp' is not debuggable 그렇다면 디버거로도 볼 수 없으니 내부 저장소에 저장한 데이터가 안전하다고 말 할 수 있을까요?그렇지 않습니다! 안드로이드는 루팅이 매우 손쉬운 운영체제기 때문에 설령 release 모드로 빌드한 앱이라 하더라도 adb 명령을 이용해 모두 접근할 수 있습니다. 루팅한 기기에서 우리가 제작한 SecureApp의 내부 저장소 구조를 아래와 같이 확인할 수 있습니다.$ adb shell "sudo ls -al /data/data/com.securecompany.secureapp" drwxrwx--x u0_a431 u0_a431 2018-06-04 14:15 cache drwxrwx--x u0_a431  u0_a431           2018-06-04 14:15 code_cache drwxrwx--x u0_a431  u0_a431           2018-06-04 14:15 shared_prefs $ adb shell "sudo ls -al /data/data/com.securecompany.secureapp/shared_prefs" -rw-rw---- u0_a431 u0_a431 111 2018-06-04 14:15 MySecureSettings.xml $ adb shell "sudo cat /data/data/com.securecompany.secureapp/shared_prefs/MySecureSettings.xml" <?xml version='1.0' encoding='utf-8' standalone='yes' ?>     별다른 테크닉이 없더라도 인터넷에 널린 수많은 루팅 방법으로 기기를 루팅하면 제아무리 내부 저장소에 저장한 데이터라도 이렇게 손 쉽게 유출이 가능하다는 것을 확인할 수 있습니다. 이런 방식의 보안 기법은 불투명성에 의지한 보안이라고 하여, 방법을 전혀 모르는 공격자에게는 유효한 방식입니다만 이 글을 읽는 독자 수준의 개발자라면 취약점을 금세 파악할 수 있다는 단점이 있습니다.그렇다면 암호화를 적용하면 되지 않을까?맞습니다. 어차피 유출을 피할 수 없다면, 데이터를 암호화하면 됩니다. 그래서 암호화 로직으로 데이터를 암호화해 보도록 하겠습니다. 이 코드는 AES / CBC / PKCS5Padding 방식을 사용해 주어진 데이터를 암호화합니다. 각 용어를 간략하게 설명하자면 다음과 같습니다.AES: 미국에서 개발된 블럭 암호화 방식으로 좀 더 나은 보안성을 가진다. 데이터를 일정 크기(블럭)로 나눠 암호화하며 보통 128비트, 192비트, 256비트 단위로 암호화한다. 키의 길이는 암호화 방식에서 사용할 블럭 크기와 완전히 같아야 하는 특징이 있다.CBC: 블럭을 회전시키는 방식을 말한다. 최초로 소개된 블럭 회전 알고리즘인 ECB(Electronic Code Book) 의 보안 취약점을 해결하기 위한 방식으로 같은 데이터 입력에 대해 완전히 다른 결과를 내므로 보안성이 좀 더 높다. 하지만 CBC 방식을 위해서는 초기화 벡터(Initialisation Vector, IV)를 반드시 사용해야 한다.IV : CBC 블럭 회전방식에 사용하는 초기화 값. 암호화할 데이터와 키가 변하지 않더라도 이 값만 바뀌면 결과가 크게 달라진다. 암호화 key 와는 전혀 무관한 값이기 때문에 외부에 노출되더라도 보안 위협은 적은 편이며 암호화 요청마다 다른 IV 를 사용해 보안성을 높일 수 있다. 다만, 키 길이와 일치하는 길이의 IV 가 필요하다.PKCS5Padding: 블럭 암호화 방식은 입력 데이터의 길이가 블럭의 길이 혹은 그 배수와 일치해야 하는 문제점이 있다. 입력 데이터가 블럭 길이보다 짧을 경우 원칙적으로 암호화가 불가능하다. 이런 어이없는 단점을 보완하기 위한 방식으로, 입력 데이터를 강제로 블럭 크기만큼 맞춰주는 알고리즘의 일종이다.object AESHelper {    /** 키를 외부에 저장할 경우 유출 위험이 있으니까 소스 코드 내에 숨겨둔다. 길이는 16자여야 한다. */    private const val SECRET_KEY = "HelloWorld!!@#$%"    private const val CIPHER_TRANSFORMATION = "AES/CBC/PKCS5PADDING"    fun encrypt(plainText: String, initVector: String): String {        val cipherText = try {            with(Cipher.getInstance(CIPHER_TRANSFORMATION), {                init(Cipher.ENCRYPT_MODE,                         SecretKeySpec(SECRET_KEY.toByteArray(), "AES"),                         IvParameterSpec(initVector.toByteArray()))                return@with doFinal(plainText.toByteArray())            })        } catch (e: GeneralSecurityException) {            // 특정 국가 혹은 저사양 기기에서는 알고리즘 지원하지 않을 수 있음. 특히 중국/인도 대상 기기            e.printStackTrace()            ""        }        return Base64.encodeToString(cipherText, Base64.DEFAULT)    }    fun decrypt(base64CipherText: String, initVector: String): String {        val plainTextBytes = try {            with(Cipher.getInstance(CIPHER_TRANSFORMATION), {                init(Cipher.DECRYPT_MODE,                        SecretKeySpec(SECRET_KEY.toByteArray(), "AES"),                        IvParameterSpec(initVector.toByteArray()))                val cipherText = Base64.decode(base64CipherText, Base64.DEFAULT)                return@with doFinal(cipherText)            })        } catch (e: GeneralSecurityException) {            // 특정 국가 혹은 저사양 기기에서는 알고리즘 지원하지 않을 수 있음. 특히 중국/인도 대상 기기            e.printStackTrace()            ByteArray(0, { i -> 0 })        }        return String(plainTextBytes)    } } [리스트 2] 간단히 구현한 AES128 암호 및 해독 로직그리고 위의 AESHelper 를 이용해 SharedPreference 에 들어갈 자료를 암호화해 봅시다.class MainActivity : AppCompatActivity() {    privateval iv by lazy { lazyInitIv() }    privateval sharedPrefs by lazy {        getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE)    }    private var appRanCount = 0    override fun onCreate(savedInstanceState: Bundle?) {         super.onCreate(savedInstanceState)        setContentView(R.layout.activity_main) // Shared preferences 는 Internal storage 에 저장된다. accessToSharedPrefs()        appRanCount++ Toast.makeText(applicationContext, "App has ran $appRanCount times!!", Toast.LENGTH_LONG).show()    }    override fun onDestroy() {        saveSharedPrefs()        super.onDestroy()    }    private fun accessToSharedPrefs() {        sharedPrefs.run({            val appRanCntEncrypted = getString(KEY_APP_RAN_COUNT, "")            if (appRanCntEncrypted.isEmpty()) {                return@run            }            appRanCount = AESHelper.decrypt(appRanCntEncrypted, iv).toInt()        })    }    private fun saveSharedPrefs() {        sharedPrefs.edit().run({            putString(KEY_APP_RAN_COUNT, AESHelper.encrypt(appRanCount.toString(), iv))             apply()        })    }    private fun lazyInitIv(): String {        return sharedPrefs.run({            var iv = getString(KEY_SESSION_IV, "")            if (iv.isEmpty()) {                // 2001년 - 2286년 동안에는 항상 13자리로 나타난다. 그러므로 16자리 IV가 보장된다.                iv = "${System.currentTimeMillis()}000"                edit()                    .putString(KEY_SESSION_IV, iv)                    .apply()            }            return@run iv        })    }    companion object {        private const val SHARED_PREF_NAME = "MySecureSettings"        private const val KEY_APP_RAN_COUNT = "appRanCount"        private const val KEY_SESSION_IV    = "ivForSession"    } } [리스트 3] 리스트 2를 활용해 데이터를 암호화해 저장.저장한 SharedPreferences 를 확인해 보면 다음과 같은 결과를 얻을 수 있습니다.$ adb shell "sudo cat /data/data/com.securecompany.secureapp/shared_prefs/MySecureSettings.xml" <?xml version='1.0' encoding='utf-8' standalone='yes' ?>    1528095873216000    F9dq8ezypMPeUsHpPIUcnQ==     역시 기대대로 암호화되었네요. IV 는 노출돼도 상관없는 정보라고 했으니 괜찮겠죠. 이제 우리 앱의 사용자는 설령 기기를 잃어버리더라도 소중한 정보가 암호화되어 있으니 문제없을 겁니다.라고 생각한다면 오산입니다! 불행히도 안드로이드는 디컴파일이 매우 쉬운 플랫폼이기 때문에 이런 식의 암호화는 사실 그다지 효과가 있지 않습니다. 심지어 IV 가 그대로 노출되어 있기 때문에 공격자에게 큰 힌트가 되었습니다. IV 는 키와는 다른 값이므로 유출되어도 상관없다곤 하지만, 어쨌든 암호화 과정에서 중요하게 다뤄지는 정보임에는 매한가지이므로 사용자에게 굳이 노출할 필요는 없습니다.다소 극단적인 예를 들어 설명했습니다만 요지는 이렇습니다. 어떤 식으로든 우리의 로직 내에서 키를 관리하는 방식으로는 완벽하게 암호화했다고 말할 수 없습니다. AESHelper 소스의 첫 줄에 있는 내용을 다시 한번 살펴봅시다. /** 키를 외부에 저장할 경우 유출 위험이 있으니까 소스 코드내에 숨겨둔다. 길이는 16자여야 한다. */    private const val SECRET_KEY = "HelloWorld!!@#$%" 불행히도 이 소스에 적힌 코멘트는 틀렸습니다. jadx 나 bytecode-viewer 로 획득한 우리 앱의 APK 파일을 디컴파일 해 봅시다.@Metadata(   mv = {1, 1, 10},   bv = {1, 0, 2},   k = 1,   d1 = {"\u0000\u0014\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u000e\n\u0002\b\u0007\bÆ\u0002\u0018\u00002\u00020\u0001B\u0007\b\u0002¢\u0006\u0002\u0010\u0002J\u0016\u0010\u0006\u001a\u00020\u00042\u0006\u0010\u0007\u001a\u00020\u00042\u0006\u0010\b\u001a\u00020\u0004J\u0016\u0010\t\u001a\u00020\u00042\u0006\u0010\n\u001a\u00020\u00042\u0006\u0010\b\u001a\u00020\u0004R\u000e\u0010\u0003\u001a\u00020\u0004X\u0082T¢\u0006\u0002\n\u0000R\u000e\u0010\u0005\u001a\u00020\u0004X\u0082T¢\u0006\u0002\n\u0000¨\u0006\u000b"},   d2 = {"Lcom/securecompany/secureapp/AESHelper;", "", "()V", "CIPHER_TRANSFORMATION", "", "SECRET_KEY", "decrypt", "base64CipherText", "initVector", "encrypt", "plainText", "production sources for module app"} ) public final class zzw {   private static final String A = "HelloWorld!!@#$%";   private static final String B = "AES/CBC/PKCS5PADDING";   public static final zzw INSTANCE; // ... } [리스트 4] 리스트 2를 디컴파일한 결과. 키가 그대로 노출됨을 확인할 수 있다.이름은 난독화했지만 문자열이 그대로 노출된 상태이므로 공격자가 단서를 찾기란 매우 쉬울 겁니다. 더군다나 원본 소스의 내용이 짧으니 아무리 난독화 했더라도 내용을 파악하기란 그리 어렵지도 않을 것이고요.여기서 일부 독자분들은 ‘그럼 이 로직을 JNI 로 만들면 되지 않냐?’ 라고 반문하실 수도 있습니다. 하지만 JNI 로 컴파일한 .so 파일조차 objdump 같은 명령으로 내용을 다 들춰볼 수 있습니다. 특히 Kotlin 구현처럼 static const 형태로 소스코드에 적어두면 공격자 입장에서는 .data 세그먼트 만 확인하면 되죠. 그렇다면 .data 세그먼트를 회피하기 위해 로직으로 키를 생성하도록 작성했다고 해 봅시다. 좀 더 난이도가 올라가긴 하겠지만 숙련된 공격자라면 .text 세그먼트를 이 잡듯이 뒤져 실마리를 찾을 수 있을 겁니다. 물론 이 정도 수준의 역공학을 할 수 있는 사람의 수는 적지만, 아예 없지는 않으니 문제는 여전히 남아 있습니다. 한번 확인해 볼까요?static const char* SECRET_KEY = "HelloWorld!!@#$%" void encrypt(char* plainText, char* initVector, char[] result) {    char* now = malloc(sizeof(char) * 13);    itoa(&time(NULL), now, 10);    char* iv = malloc(sizeof(char) * 16);    strcpy(iv, *now);    strncpy(iv, "000", 3);   const struct AES_ctx aesCtx = { .RoundKey = 16, .Iv = *iv }    AES_init_ctx(aesCtx, SECRET_KEY);    // ... } [리스트 5] C 로 작성한 AESHelper 로직(일부).$ objdump "mySecureApp/build/obj/local/armeabi-v7a/libAESHelper.so" section .data    # 의미 불명의 문자열 발견! 혹시 key 는 아닐까???    00000200 db "HelloWorld!!@#$%", 16    00000210 equ $ - 00000200 section .text    global _start    _start:    # ...        mov rsi, 00000200  # 이 명령 앞뒤로 조사해보면 저 문자열의 용도를 파악할 수 있다.        mov rdx, 00000210        syscall    # ... [리스트 6] ARM EABI V7용으로 컴파일한 바이너리를 디스어셈블 한 결과.즉, 어떤 방식으로 구현하건 암호화에 쓸 키를 소스 코드에 박아두는 것은 그다지 현명한 선택이 아니란 것입니다. 더군다나 안드로이드에서 앱을 만든다는 것은 내 로직이 공격자에게 낱낱이 까발려져 있다는 것을 의미합니다. 중요한 데이터를 .text 에 들어가도록 숨기는 것도 가능하긴 하지만, 그런 방식은 나중에 유지보수하는 사람에게도 골치 아플 겁니다. 소스 코드가 그만큼 어려워질 테니까요. 그리고 그런 방식으로 정보를 숨긴다 하더라도 최정예 크래커 집단, 예를 들어 국정원 같은 수준이라면 그 정도는 큰 어려움 없이 파훼 가능합니다.꿈도 희망도 없는 상황처럼 보입니다만 다행히도 안드로이드는 이런 문제를 해결해 주는 KeyStore API 를 제공하고 있습니다.KeyStore 를 도입하자Android KeyStore 시스템 문서의 첫 머리에 적혀있는 글은 다음과 같습니다.The Android Keystore system lets you store cryptographic keys in a container to make it more difficult to extract from the device. Once keys are in the keystore, they can be used for cryptographic operations with the key material remaining non-exportable. Moreover, it offers facilities to restrict when and how keys can be used, such as requiring user authentication for key use or restricting keys to be used only in certain cryptographic modes.Android Keystore 시스템은 암호화 키를 ‘컨테이너’ 에 저장하도록 해 기기에서 키를 추출하기 더욱 어렵게 해 줍니다. 일단 키를 Keystore 에 저장하면 키를 추출 불가능한 상태로 암호화에 사용할 수 있습니다. 또한 Keystore 는 키 사용 시기와 방법(예: 사용자 인증 등의 상황)을 통제하고, 특정 암호화에서만 키를 사용하도록 허용하는 기능도 제공합니다.좀더 쉽게 다시 설명하자면, 암호화에 쓸 키를 소스코드 내부 어딘가가 아니라, 시스템만이 접근 가능한 어딘가(컨테이너)에 저장해 문제를 해결해 준다는 뜻입니다. 여기서 키가 저장되는 ‘컨테이너’ 는 기기별로 구현이 다를 수 있습니다만 핵심은 사용자 어플리케이션이 그 영역에 접근할 수 없다는 점입니다. 이 때문에 KeyStore 를 사용해서 키를 안전하게 저장할 수 있습니다.또한 앱에서 등록한 KeyStore 는 앱 삭제 시 함께 제거되므로, 똑같은 package name 으로 앱을 덮어씌우는 등의 공격으로 키를 유출할 수도 없습니다. 이는 여러 앱에서 공유하는 KeyChain 과는 다른 특성이며 기능 활성화를 위한 별도의 입력이 필요 없다는 장점이 있습니다.[그림 1] KeyChain API 사용시 나타나는 시스템 다이얼로그. 어려운 용어가 난무하는 등 사용자 경험이 그다지 좋다고 말할 수 없다.반면 Android M 이상에서는, KeyGenParameterSpec.Builder#setUserAuthenticationRequired(boolean) API 로 시스템 다이얼로그의 표시 유무를 제어할 수 있습니다.Secure SharedPreferences 구현하기앞서 설명드렸던 KeyStore 를 사용해 SharedPreferences 의 내용을 암호화하는 로직입니다. 소스 코드의 길이가 꽤 길기에, github gist 링크로 대신합니다. 독자 여러분들을 위해 최대한 쉽고 간단한 형태로 구현했으므로 필요에 맞춰 커스터마이징 하는게 좋습니다.AndroidCipherHelper.kt - KeyStore 에서 생성한 랜덤 패스워드를 이용해 입력받은 문자열을 암호화 하는 로직. IV 설정 등 귀찮은 작업을 피하기 위해 비대칭 암호화 알고리즘을 사용했다. 또한 암호화 및 복호화 과정에서 비대칭키의 Public key 로 암호화하고, Private key 로 해독하도록 구현했다. TEE 를 올바르게 구현한 기기(안드로이드 23 이상 + 메이저 하드웨어 제조사)에서 동작하는 한, 이 데이터의 내용이 유출되더라도 복호화는 오직 이 로직 내부에서만 할 수 있다.SecureSharedPreferences.kt - AndroidCipherHelper 가 문자열 위주로 암호화하므로, 모든 입력값을 문자 형태로 변환 후 입출력한다.결과 확인Secure SharedPreferences 를 실제로 구현한 뒤, 앱의 shared preferences 를 열어보면 아래와 같은 결과가 나타납니다.$ adb shell "run-as com.securecompany.secureapp cat /data/data/com.securecompany.secureapp/shared_prefs/MySecureSettings.xml" <?xml version='1.0' encoding='utf-8' standalone='yes' ?>     oh+XL/vQqAdxNzFEkKVOfcZAkP7jh92tcKpxzM6bbv9iGUk2lR7ayJsR6FZXt3rAKC+4sLVTP1cy e+NpgZ67wjoeBM4maMjXjSkovc8cO8rVVsQLqedJtW3gGOItTTCkjIQGh+TsBDjz8C3IdmNSKqGE GmBwQBoV0QuO+uO6cdPI/Gx816P0kcLmr5xsAy9XUwJeTE9947sYydiztJsgkKxuiGFLJK435pAb UhatjSFse4MpBCugHcLUVg5UXGwQcfbJuuQ/CBcmQmYb3MldNzLfOWtsQiwQJpz0J12fsYlQOBnO UnLVcND+DU17cP+Q4Cjah8VwmiY1a0shMn09Rw==         ozh8dKH+yCRSWoiW0HQtF/bWD7Aw6rfjzklT302AlTOpYmVdEiIfVoTK97bsyK1mXbwN5Qpas82Q dYgnnZl9sfY8pzyXHM0dtm88euB5vgmzljb04LClF3oRZ7Qi5ZRyK90kQ/HN/6EgYvf6zEwR7Ydg 08kJ/bde4Z5lSz+kJ79dHEpE+QAV48U0F0/yp12+xKFRNbaBLBaaWclUNF10jONPKjC3HS/aQozT 1ngQWSKzPq87B0OFExraSPDoLT8zx8ElhTgEtpBRcUwtzmSnhGvgtIUhziFpZBbdvuqAGZ+L5El1 T7H9ipEosN3Aivh/5rz9dntJe3mJvfCFdFITlA==     (Android L 이상이라고 가정할 경우)앱의 개발자조차 키를 알 수 없기 때문에, 파일을 유출하더라도 이를 깨는것은 현재로선 매우 어렵습니다. 즉, 우리 앱은 사용자 데이터를 안전하게 보호하고 있다고 자신 있게 말할 수 있습니다.AndroidKeyStore 파헤쳐보기그렇다면 어떤 방식으로 AndroidKeyStore 가 동작하고, 왜 안전한지 좀더 상세히 살펴보겠습니다.“AndroidKeyStore” 문자열의 중요성Android Keystore system 문서에 따르면 Android Keystore Service 에 접근하기 위해서는 아래와 같이 코드를 작성해야 한다고 합니다. val keyStore = java.security.KeyStore.getInstance("AndroidKeyStore") [리스트 7] Android Keystore 인스턴스 획득 방법여기서 주의할 점은 AndroidKeyStore 라는 문자열입니다. 반드시 정확한 문자열로 입력해야 합니다. 왜냐면 이는 Google 이 안드로이드의 보안 시스템을 Java Cryptography Architecture(JCA) 표준에 맞춰 구현했기 때문에 그렇습니다. 그리고 JCA 표준을 구현하면 JVM 인스턴스(안드로이드도 변형 JVM 의 일종입니다) 내에서 동작하는 모든 로직이 Security 클래스에 등록된 암호화 구현체를 사용할 수 있게 됩니다. 즉, Google 이 컨트롤 할 수 없는 서드파티 로직(우리의 앱 혹은 각종 안드로이드 오픈 소스들)에서도 Android Keystore 를 표준 Java 방식으로 사용할 수 있도록 구현했기에 이런 방식으로 호출해야 하는 겁니다.물론 안드로이드에서는 AIDL 파일을 제공받는 방식 혹은 Context#getSystemService(String) 메소드로 서비스 인스턴스를 획득할 수도 있습니다. 하지만 첫 번째 방식은 바인드된 서비스가 언제든 Kill 될 수 있다는 문제가 있습니다. 그리고 두 방식의 공통적인 문제점은 보안을 사용하는 모든 로직에 if (currentEnvironment == "Android") then... 같은 예외 처리 로직을 넣어줘야 한다는 점입니다. 전 세계 모든 오픈소스 개발자들이 안드로이드로의 포팅을 위해 그런 귀찮은 작업을 해 줘야 하는 일인데.. 그게 가능할까요?“AndroidKeyStore” JCA Provider 등록 과정앞서 AndroidKeyStore 라는 문자열의 중요성을 알아봤습니다. 그렇다면 왜 중요한지도 알아두면 좋겠죠?안드로이드는 linux 기반의 운영체제입니다. 시스템 부팅 직후 실행되는 init.rc 스크립트에서는 /system/bin/app_process 명령을 실행하는데 이 명령은 Android Runtime 위에서 실행되는 Zygote process를 초기화 합니다.Zygote 는 간단하게 설명하자면 안드로이드 앱 실행속도를 향상시키기 위한 일종의 공용 런타임 같은 것입니다. 그리고 앱이 실행되면 Zygote 에 설정된 내용이 사전에 로드되는데, 아까 언급한 초기화 과정 중에 아래와 같은 내용이 있습니다.package com.android.internal.os; /**  * Startup class for the zygote process.  *  * Pre-initializes some classes, and then waits for commands on a UNIX domain  * socket. Based on these commands, forks off child processes that inherit  * the initial state of the VM.  *  * Please see {@link ZygoteConnection.Arguments} for documentation on the  * client protocol.  *  * @hide  */ public class ZygoteInit {    private static final String TAG = "Zygote"; /**     * Register AndroidKeyStoreProvider and warm up the providers that are already registered.      *     * By doing it here we avoid that each app does it when requesting a service from the      * provider for the first time.      */     private static void warmUpJcaProviders() {        // ...        // AndroidKeyStoreProvider.install() manipulates the list of JCA providers to insert        // preferred providers. Note this is not done via security.properties as the JCA providers        // are not on the classpath in the case of, for example, raw dalvikvm runtimes.        AndroidKeyStoreProvider.install();        Log.i(TAG, "Installed AndroidKeyStoreProvider in "                 + (SystemClock.uptimeMillis() - startTime) + "ms.");        // ...    } // ... } [리스트 8] ZygoteInit.java 의 JCA provider 설치 및 속도향상 과정package android.security.keystore; /**  * A provider focused on providing JCA interfaces for the Android KeyStore. *  * @hide  */ public class AndroidKeyStoreProvider extends Provider {    public static final String PROVIDER_NAME = "AndroidKeyStore";    public AndroidKeyStoreProvider() {        super(PROVIDER_NAME, 1.0, "Android KeyStore security provider");        // ...    } /**     * Installs a new instance of this provider.     */    public static void install() {        // ....        Security.addProvider(new AndroidKeyStoreProvider());        // ...    } } [리스트 9] AndroidKeyStoreProvider.java - “AndroidKeyStore” 라는 이름의 JCA provider 등록 과정이런 일련의 과정을 거쳐 시스템에서 등록한 AndroidKeyStore 라는 이름으로 Android KeyStore 서비스에 접근할 수 있게 됩니다. 그리고 안드로이드에서 사용 가능한 KeyStore provider 들의 종류를 뽑아보면, 아래와 같은 결과가 나타납니다.// List all security providers for (Provider p : java.security.Security.getProviders()) {    System.out.println(String.format("== %s ==", p.getName()));    for (Provider.Service s : p.getServices()) {        System.out.println(String.format("- %s", s.getAlgorithm()));    } } output: == AndroidKeyStoreBCWorkaround == == AndroidOpenSSL == ... == AndroidKeyStore ==    - AndroidKeyStore     - HmacSHA256    - AES    ... [리스트 10] 안드로이드 M(6.0.1)에서 지원하는 KeyStore provider 목록(중요) AndroidKeyStore 의 Hardware 레벨 지원 여부 확인다시 Android KeyStore 시스템의 설명으로 돌아가 봅시다.Key material of Android Keystore keys is protected from extraction using two security measures:…Key material may be bound to the secure hardware (e.g., Trusted Execution Environment (TEE), Secure Element (SE)) of the Android device. When this feature is enabled for a key, its key material is never exposed outside of secure hardware.Android KeyStore 는 키의 추출을 방지하기 위해 두 가지 보안 조치를 사용합니다:…키는 안드로이드 기기의 보안 하드웨어(e.g., Trusted Execution Environment (TEE), Secure Element (SE)) 에서만 동작할 수 있습니다. 이 기능이 활성화되면 키는 절대로 보안 하드웨어 밖으로 노출되지 않습니다.그런가보다 싶지만 유심히 읽어봐야 할 대목이 있습니다. 바로 Key material may be bound to … 부분입니다. is 가 아니라 may be 랍니다. 즉, 키가 하드웨어에 저장되지 않을 수도 있다는 사실입니다. 물론 문서에는 언급되어 있지 않지만 안드로이드 시스템 특징상 제조원가 절감을 위해 디바이스 제조사들이 KeyStore 를 소프트웨어로 구현할 수도 있다는 뜻입니다. AOSP 의 Keymaster 구현을 살펴보면 sw_enforced 라는 키워드가 있습니다. 이 keymaster API 를 하드웨어 제조사에서 Keymaster HAL 을 통해 호출하는데 만약 sw_enforced 인스턴스를 넘기는 형태로 구현할 경우 그 하드웨어는 KeyStore 를 지원하지만 (API Level 18), 그것이 반드시 별도의 보안 하드웨어 위에서 동작한다고 말할 수는 없습니다.그리고 “Inside Android Security” 의 저자 Nicolay Elenkov 에 의하면 Android M 이전의 Software-backed KeyStore 는 root 된 기기에서 유출 가능하다고 합니다. 링크의 내용이 다소 길기 때문에 요약하자면 software 기반의 KeyStore 구현은 키를 /data/misc/keystore/user_X(여기서 X 는 uid - 시스템이 앱마다 부여하는 id)에 저장하는데 이 파일의 내용은 keystore-decryptor 로 풀어볼 수 있다고 합니다. 그리고 하드웨어 보안을 지원하지 않는 기기를 확보하지 못해 실 기기에서는 확인할 수 없었습니다만, 에뮬레이터에서 실제로 확인해 본 결과 사실이었습니다.즉, (Android KeyStore)를 쓰더라도 Android M 이전의 기기에서는 우리 앱의 데이터가 100% 안전하다는 장담을 할 수는 없습니다. 아직까지 이 문제를 해결할 방법은 찾지 못했습니다만 아래와 같은 로직으로 ‘이 기기에서의 앱 실행은 안전하지 않을 수 있다’ 같은 안내를 띄우는 정도의 가이드는 개발 가능합니다.val privKey = (keyEntry as KeyStore.PrivateKeyEntry).privateKey val factory = KeyFactory.getInstance(privKey.getAlgorithm(), "AndroidKeyStore") val keyInfo: KeyInfo try {    keyInfo = factory.getKeySpec(privKey, KeyInfo::class.java)    println("HARDWARE-BACKED KEY???? " + keyInfo.isInsideSecureHardware) } catch (e: InvalidKeySpecException) {    // Not an Android KeyStore key. e.printStackTrace() } [리스트 11] KeyInfo API 로 키가 하드웨어로 안전하게 보호되고 있는지를 확인하는 방법다행히도 저희가 보유 중인 개발 시료에서 모두 확인해본 결과 모두 true 로 확인되는 것으로 보아 전 세계의 대중적인 API Level 18 이상인 Android 기기에서는 KeyStore 를 안심하고 사용할 수 있다는 결론을 얻었습니다.다만 API Level L 이전의 Android KeyStore 에는 사용자가 Lock screen 을 설정하지 않을 경우 초기화 된다거나, 직접 확인하진 못했지만 앱을 삭제하더라도 KeyStore 가 완전히 초기화되지 않는 등의 문제도 있다고 하니 유의하는 것이 좋겠습니다.맺으며이상으로 KeyStore 를 사용해 데이터를 암호화하는 방법에 대해 알아봤습니다. 저희 하이퍼커넥트에서도 현재 제작 중인 안드로이드 앱 일부에서 이 기능을 탑재해 고객 여러분들의 데이터를 안전하게 보호하려 노력하고 있습니다. 또한 iOS 도 Secure enclave라 하여 비슷한 기능을 제공하고 있으며 역시 저희 개발진은 이 기술의 적극 도입을 위한 노력을 진행 중입니다.물론 여기 적혀있는 내용들은 Android M(API Level 23) 이후에서만 100% 안전하기 때문에 저희는 그 이전의 안드로이드 버전에서도 데이터를 안전하게 저장할 방법에 대해 지금도 계속 고민 중입니다.또한 눈치 빠른 독자분들은 이 기법을 잘 응용하면 외부 저장소에 저장하는 파일도 암호화 할 수 있다는 사실을 깨달으셨을 겁니다. 이 기법은 요즘 데이터 불법 유출로 몸살을 앓고 있는 웹툰 앱들에도 유용합니다. 임시로 다운로드 한 이미지 파일을 KeyStore 가 생성해주는 키로 암호화해 버리고, WindowManager.LayoutParams#FLAG_SECURE 를 사용해 화면 캡쳐까지도 막아버린다면 대부분의 어설픈 유출 시도는 손쉽게 막으실 수 있으리라 생각합니다.꽤 길었던 1부가 끝났습니다. 2부에서는, 2017년 5월에 소개된 Room을 사용한 안드로이드 데이터베이스를 암호화하는 법에 대해 소개하겠습니다.더 보기Android KeyStore 시스템블록 암호 운용 방식초기화 벡터문자 인코딩AES 암호화RSA 암호화Padding(Cryptography)AOSP KeyStore implementation requirementsHow the Android keystore system can be secureJCA reference guideUnderstanding Android zygote and DalvikVMAndroid InternalsKeystore redesign in Android M - by Nicolay ElenkovAnalysis of Secure Key Storage Solutions on Android#하이퍼커넥트 #개발 #개발자 #안드로이드 #모바일 #앱개발 #PersistentData #개발후기 #인사이트
조회수 733

일의 문턱에서, 못난 나를 마주할 때.

선생님들이 일에 적응이 되고 주도적으로 움직이며 안정을 찾기 까지 꽤 시간이 걸렸다. 그리고 비로소, 아 이제 우리 같은 마음과 에너지로 가고 있구나! 라는 마음이 들기 시작했다. 회사에도 내 마음에도 안정감이 찾아온다.이렇게 되기 까지 몇번의 고비가 지나간 것 같다. 지난 몇달 간 선생님들은 개인적으로 번갈아 가며 내적인 고민을 털어놓았다. 엄마가 갑자기 일을 하게 되면서 찾아온 아이들의 마음변화, 그것을 바라보며 '과연 괜찮을까?' 요동쳤던 마음, 빨리 적응하고 잘하고 싶은데 마음을 따라가주지 않는 집중력과 체력, 너무 오랜만이라 낯설기만 한 문서와 엑셀작업들, 왜 한번에 이해를 못하는걸까? 무능해진것만 같은 스스로를 탓하는 마음.  호소하는 그 수 많은 감정의 고비를 몇 번이고 지나며 한 분씩 안정을 찾기 시작했고, 이제는 누구보다 주도적으로 기쁘게 일을 끌고 나가는 모습을 보며 나 역시 큰 보람을 느끼게 된다.생각해보면 공백을 깨고 다시 일을 시작했을 때 나역시 비슷한 과정을 겪었던 것 같다. 강의를 하다가 모든 것이 블랙아웃 되어 어버버 하기도 하고, 설명하는 것을 한번에 따라잡지 못해서 멍해지는 나를 탓하기도 했으며, 내가 도저히 통제할 수 없는 아이와 관련된 변수 때문에 주변 사람들에게 미안한 마음을 늘 달고 살아야 했었다.그 고비를 지나갈 수 있었던것, 포기하지 않고 올 수 있었던 것은 다름 아닌 또 다른 엄마동료의 지지였다. 누군가에게 이런 속내를 나눌 수 있다는 것 만으로도, 쪼그라지고 그저 못나게만 느껴지던 그 때의 나를 다독일 수 있었던 것 같다. 혼자 스스로를 자책하며 시간을 보냈다면 나는 오래 버티지 못했을지도 모른다.우리 그로잉맘 선생님들과 함께 또 같은 고비를 넘으며, 나는 우리가 서로에게 그런 존재가 되어 줄 수 있었으면 좋겠다는 생각을 했다.지금은 엄마로만 살고 있지만 언젠가는 나의 점을 하나 더 찍어야 할텐데- 라고 생각하며 막막함을 느끼는 마음도, 다시 시작하는 일의 문턱에서 쪼그라들며 무기력해지는 마음도, 일을 병행하지만 여전히 시시때때로 갈등하며 스스로에게 죄책감을 주게 되는 마음도 모두 다 엄마라는 시간안에 연결되어 있는 감정들이 아닐까?그렇기에 나는 우리가, 서로가 서로에게 들어주는 존재가 될 수 있다고 믿는다. 서로의 마음을 가장 잘 아는 우리는 '엄마' 라는 같은 이름을 가지고 있으니까.#그로잉맘 #경단녀 #경력단절여성 #엄마도경력이다 #육아와업무 #스타트업CEO #일하는엄마 #기업문화 #여성복지 #엄마동료
조회수 1017

DevOps 문화 안에서의 APM의 역할 [1] (DevOps+JENNIFER)

 DevOps의 시작언제나 그랬듯이 소프트웨어 개발 트렌드는 계속 변화하고 있다. A부터 Z까지 모든 것을 새롭게 개발했던 것과 달리 아키텍처나 사용하는 용도에 따라 개방형 플랫폼이나 오픈소스 등을 활용하여 원하는 소프트웨어를 쉽게 개발할 수 있게 되었다. 또한 클라우드로 인해 애플리케이션과 서비스 개발에 대한 새로운 패러다임이 나타나고 있다. 기존의 온-프레미스 환경에서는 물리적 서버 준비, 운영체제 설치, 서비스 배포 등에 수많은 시간이 걸렸지만, 클라우드를 활용하면서 단시간에 원하는 자원을 준비하고 배포할 수 있게 되었다.이러한 변화로 개발자의 영역이 좀 더 넓어지는 계기가 되었다. 이는 전통적인 비즈니스 환경에서 개발, 빌드, 테스트, 배포, 운영에 이르는 프로세스를 효율적으로 운용할 수 있게 되어 고객의 요구사항을 빠르게 반영할 수 있게 되었다. 이것이 바로 DevOps의 시작이다. 하지만 다양한 오픈소스의 탄생과 클라우드 환경의 확산 등으로 인해 정말로 새로운 기능에 대한 개발이 빨라졌을까? 그렇다면 이에 따른 문제는 없을까? 개발 프로세스의 병목 구간DevOps의 필수 조건인 테스트 및 배포의 자동화가 이뤄지면 운영 단계에서는 반영된 사항들에 대해 주기적으로 모니터링을 해야 한다. 만약에 반영된 소스코드에 장애를 발생시킬 수 있는 잠재적 버그가 존재한다면 이를 어떻게 운영 단계에서 찾을 수 있을까? 예를 들어 특정 서비스의 피크타임에 부하가 급증한다면 앞서 말한 상황에 대한 버그가 발생할 확률이 상대적으로 높아진다. 하지만 장애의 원인이 될 수 있는 요소는 매우 다양하기 때문에 단순히 트래픽 문제로 속단할 수는 없다.직접 개발한 소프트웨어만의 문제가 아닐 수도 있으며, 제품 개발시 생산성 향상을 위해 도입된 다른 종류의 오픈소스에서 문제가 될 수도 있다. 실은 이런 류의 프로젝트들은 상용 제품이 아니므로 문제가 발생하면 상당히 곤란한 경우가 생기곤 한다. DevOps를 위한 환경이 구성되고, 고객의 요구사항을 빠르게 반영할 수 있는 시스템이 갖춰졌더라도 결국에는 앞서 말한 다양한 종류의 잠재적, 환경적인 문제들로 인해 병목이 발생할 수 있다.  모니터링 단계에서 APM의 역할개발 프로세스의 마지막 관문인 모니터링 단계는 DevOps에서 매우 중요한 역할을 한다. 하지만 안타깝게도 이미 반영된 실제 서비스에서 모니터링을 성공적으로 마치고 피드백 수집 단계로 넘어가기 위해서는 앞서 말했던 장애의 원인을 빠르게 진단해야 한다. 경우에 따라 많은 시간이 소모되기도 하기도 하며, 이는 바로 생산성 저하로 이어진다. 또한 새로운 프로세스 진행을 더욱더 보수적으로 만드는 원인이 된다.DevOps를 완벽하게 실현하기 위해서는 모니터링 단계에서 서비스 배포 이후의 서버에 들어오는 트랜잭션에 대한 상태를 배포 전과 비교할 수 있어야 하며, 응답을 지연시킬만한 요소들을 빠르게 인지할 수 있어야 한다. 그리고 배포된 소스코드로 인해 서비스 장애가 발생하는 상황이 온다면 이를 처리하기 전까지 어떻게든 서비스 장애를 지연시켜야만 한다. 이러한 이유로 DevOps 진영에서는 APM의 역할은 매우 중요한 이슈이다. 우리는 제니퍼를 통해 앞서 말한 기능들을 활용하는 방법에 대해 알아볼 것이다. 모니터링 프로세스모니터링 단계는 아래 그림과 같이 문제의 발견 및 조치, 문제해결시 재배포 단계로 나눌 수 있다.  제니퍼 대시보드를 통해 액티브서비스 상태와 트랜잭션 변화 추이를 모니터링 할 수 있는데, 만약에 새로 배포된 소스코드에 문제가 있다면 처리 중인 액티브서비스가 쌓이게 되고 , 트랜잭션 분포도 차트는 기존에 그려졌던 패턴과 다르게 보여지게 된다.이런 시점에 운영에서는 설정 여부에 따라 이벤트를 발생 시킬 수 있다. E-Mail이나 SMS, Slack과 같은 메신저 등으로 각각의 담당자들에게 서비스 상태를 알려줄 수 있으며, 담당자에게 이벤트 메시지가 전달되었다면 제니퍼를 통해 두가지 조치를 할 수 있게 된다. 먼저 개발자는 스마트 프로파일링 기능을 통해 원인분석을 하고, 운영에서는 서비스가 최악의 상태가 되기 전에 트랜잭션 유입을 차단하여 다른 화면으로 리다이렉트 시켜주는 PLC 기능을 사용할 수 있다.제니퍼에서는 서버에서 하나의 요청에 대한 처리가 끝나면 곧바로 수집되는 데이터를 트랜잭션이라하며, 현재 수행 중인 상태에 대한 실시간 데이터를 액티브서비스라고 정의한다.   모니터링 기준 값 설정서비스를 배포하기 전에 모니터링 단계를 원활하게 수행하기 위해서는 제니퍼 관리 화면에서 몇가지 설정을 해야한다. 먼저 서비스 장애 발생시 이벤트 알림 및 서비스 부하량 제어 설정의 기준이 되는 값인 전체 에이전트의 평균 액티브서비스 개수를 알아야 한다. 하지만 서비스가 운영되는 환경에 따라 기준 값이 너무 다르기 때문에 어느 정도 안정적으로 서비스가 운영되고 있다고 생각하는 시점에 대략적으로 기준 값을 정하면 된다.에이전트란 모니터링 대상 애플리케이션에 기생하여 성능 데이터를 수집하고, 이를 서버로 전송하는 역할을 하는 모듈을 말한다. 참고로 모니터링 대상 애플리케이션은 플랫폼 환경에 따라 차이가 있을 수 있는데, 일반적으로 WAS(Web Application Server)나 웹 서버를 말한다.  액티브서비스는 처리가 완료되지 않은 상태이므로 서비스 장애의 원인분석을 위한 데이터로는 적합하지 않다. 그렇기 때문에 액티브서비스 개수는 기준 값이 될 수 없으며, 개발자는 처리가 완료된 트랜잭션 데이터의 응답시간을 기준 값으로 제니퍼의 프로파일링 관련 설정을 해야 한다. 설정된 값을 기준으로 트랜잭션 분포도 차트에서 가상의 선을 긋고, 그 선 위에 있는 트랜잭션을 대상으로 스마트 프로파일링 기능을 수행할 수 있다.  본문에서는 모니터링 단계에서 직면하게 되는 문제점과 이를 해결하기 위한 APM의 역할과 필요성 대한 이야기를 했다. 다음 편에서는 본격적으로 제니퍼를 활용하여 모니터링 프로세스를 어떻게 수행하는지에 대해 알아볼 것이다.2편에서 계속...
조회수 2320

Good Developer 4 | 학습하는 개발자 -고농축 학습 자료 꿀팁

더 이상의 설명은 필요 없다.지금까지 우리는 Good Developer 시리즈는 커뮤니케이션과 나쁜 개발자의 습관을 통해 좋은 개발자가 무엇인지 알아보았다. 이번에는 좋은 개발자가 되기 위한 가장 중요한 조건 바로 학습하는 개발자에 대해 알아볼 것이다.개발자가 새로운 것을 익히고 배우는 것은 너무도 당연하다. 이것에 대해 글을 쓰는 것은 의미가 없는 것 같아서 많은 고민을 했다. 그래서 실질적으로 학습에 도움을 줄 수 있는 아주 고농축 꿀팁들을 주면 좋은 개발자가 되는데 도움이 되지 않을까 생각했다. 이번 편은 학습하는 개발자 - 고농축 학습 꿀팁 편이다.학습은 천천히, 그러나 꾸준히너무나 당연한 말을 한 번 더 하고 시작할까 한다. 개발뿐만 아니라 모든 학습이 마찬가지겠지만, 꾸준히 학습해야 하는 개발자에게 중요한 것은 학습 습관이다. 이것저것 깨작깨작 찔러보고 공부하는 깊이로는 새로운 기술들을 자신의 것으로 만들 수 없으며 오히려 시간을 낭비하는 것일 수도 있다. 하나의 기술을 배우기 시작했으면 서두르지 말고 천천히 음미하면서 학습해야 한다. 그 대신 한두 달 공부하고 끝내는 것이 아니라 충분한 깊이를 가질 때까지 꾸준히 학습하라!직장을 다녀본 사람은 알 것이다. 직장을 다니면서 따로 자기개발을 하고 학습을 하는 것이 쉽지 않다는 것을 말이다. 하지만 좋은 개발자, 더 나은 개발자가 되기 위해서라면 학습을 멈춰 서는 안된다. 그것이 개발자의 숙명이다. 그래서 개발은 정말 개발을 좋아하는 사람만이 할 수 있는 직업인 것 같다. 혹시 자신이 학습을 하는데 있어 자꾸 포기하게 되고 중단하게 된다면 이전에 썼던 '글로 배우는 코딩 1 | 포기하지 않고 끝까지 공부하는 법'편을 참고해보길 바란다.아래의 학습 정보들은 많이 알 수도 있는 정보지만, 개발자가 되려는 사람들, 잘 모르는 사람들에게는 분명히 좋은 정보가 되리라 생각한다. 알고리즘 사이트 Top 31. 백준 온라인 저지백준 저지는 1만 개 이상의 알고리즘 문제를 보유한 사이트다. 타 사이트에 비해 홈페이지 구성도 잘 되어 있고 문제도 잘 나누어져 있다.그리고 사람들이 문제들을 골라서 자신만의 문제집을 만들어서 공유하기도 한다. 또한 알고리즘 지원 언어도 60개 이상이기 때문에 어떤 언어를 공부하든 웬만해서는 문제없이 풀 수 있다.(이런 언어도 있나 싶을 정도로 많은 언어들의 채점을 지원하고 있다.)기회가 되면 언어들을 직접 세어보는 것도......Baekjoon Online JudgeBaekjoon Online Judge 프로그래밍 문제를 풀고 온라인으로 채점받을 수 있는 곳입니다. 14264 전체 문제 11797 채점 가능한 문제 9316 풀린 문제 64 채점 가능한 언어www.acmicpc.net2. 코드워즈(codewars)코드워즈는 게임 형식의 알고리즘 학습 사이트다. 약 20여 개의 언어를 지원하며, C, C++ C#, Go PHP, JAVA, Python 등 주요 언어들은 모두 지원한다. UI/UX적으로도 굉장히 구성이 잘 되어 있고 인터페이스만 익숙해지면 정말 좋은 코딩 학습 사이트다.영어 사이트이긴 하지만 어느 정도의 독해 수준이면 충분히 학습할 수 있다. 게임 형식으로 알고리즘을 풀기 때문에 정말 재미있게 알고리즘을 학습할 수 있는 사이트! 알고리즘 사이트 중 가장 추천하는 사이트다. 태그도 잘 되어 있어서 function, array, data types 별로 자신이 약한 부분을 집중적으로 학습할 수도 있다.Codewars: Train your coding skillsCodewars is where developers achieve code mastery through challenge. Train on kata in the dojo and reach your highest potential.www.codewars.com3. 프로그래머스프로그래머스는 단계적으로 알고리즘 문제를 풀어볼 수 있는데 최적화된 사이트다. 레벨 1부터 레벨 8까지 정리된 프로그래밍 알고리즘을 풀 수 있다. 지원되는 언어가 C++ 자바 파이썬 자바스크립트로 가장 많이 쓰는 언어만 지원한다는 단점이 있다.모든 문제가 한글이라서 영어가 부담되시는 분들에게는 체계적으로 부담 없이 할 수 있다. 문제를 풀고 제출하는 환경도 잘 구성되어 있어 편리성이 좋은 알고리즘 학습 사이트다. 다만, 다른 사이트 들에 비해 문제의 수가 적다는 점! 영어가 부담되고 단계별로 알고리즘 문제를 풀고 싶다면 이 사이트를 추천한다.프로그래머스동영상과 실습으로 구성된 최고의 프로그래밍 강좌를 만나세요. 프로그래머스에서는 프로그래밍 강좌, 알고리즘 문제, 프로그래밍 대회, 블록체인 자료를 만날 수 있습니다.programmers.co.kr코딩 학습 사이트 Top 51. 유데미(Udemy)엄청나게 질 좋은 강의를 엄청나게 저렴한 가격으로 이용할 수 있는 곳! 1만 원대의 강좌에서 이 정도 퀄리티의 학습 콘텐츠를 얻기는 유데미 외에서는 불가능할 것이다.(광고 글이 아니다 정말이다.) 강의의 분야와 주제도 많고(개발 외에도 여러 가지가 있다) 짧게 짧게, 5~7시간 커리큘럼의 강의들이 많아서 부담 없이 학습할 수 있는 사이트. 강의 수준도 초급부터 고급까지 다양해서 수준 있는 개발자들도 들을 강의가 많다.대부분이 영어 강의이기는 하지만 요즘 한국 강사들의 유입도 늘어서 한국 강의도 늘고 있는 추세다. 영어 자막도 제공하니 영어를 읽을 수만 있다면 강력 추천하는 학습 사이트다.글을 클릭하면 유데미 사이트로 이동합니다.2. 코드카데미(codecademy)체계적으로 코딩을 배우고 싶은데 무료로 배우고 싶다면?! 바로 코드카데미다. 동영상은 보기 귀찮고 읽으면서 단계적으로 코딩을 배우고 싶다면 코드카데미가 적격이다. 자바스크립트를 주축으로 하는 개발 도구 위주만 배울 수 있다는 단점이 있지만, 코딩을 직접 하면서 배울 수 있다는 큰 장점이 있기 때문에 동영상 강의만 보고 그냥 넘길 수 있는 다른 사이트와는 다르게 바로바로 코딩을 쓰면서 배울 수 있다. 역시 영어 학습 사이트지만 개발자가 되기 위해서 필요한 영어 실력만 가지고 있어도 충분히 학습해 나갈 수 있다.Codecademy - learn to code, interactively, for freeCodecademy is the world's most popular way to learn over 12 coding languages including HTML, CSS, JavaScript, Python, SQL, and Ruby. Sign up today and start learning to code in minutes.www.codecademy.com3. 코드스테이츠한국 최초의 코딩 부트 캠프 코드스테이츠. 코드스테이츠 입장에서 코드스테이츠를 추천하는 것이 민망해해 보일 수 있어도, 그만큼 자부심이 있다. 온/오프라인 교육이기 때문에 다른 온라인 교육 사이트보다 저렴하지는 않지만, 개발자를 꿈꾼다면 일정 금액을 투자하고 개발자가 확실히 될 수 있다는 장점이 있다.  온/오프라인에서 직접 멘토링을 받아 가면서 학습을 하고 싶다면 코드스테이츠를 강력 추천한다.온라인 학습과 오프라인 코칭으로 온라인 콘텐츠와 오프라인 교육을 둘 다 가져갈 수 있다는 장점이 있다. 코스 중간에 미니 해커톤과 실제 기업과 협업 프로젝트를 진행해 볼 수 있다는 것도 큰 장점! 단점은 다른 온라인 학습 사이트에 비해서는 가격이 어느 정도 있다.코드스테이츠 | 혁신적인 코딩 교육 부트캠프코드스테이츠(Code States)는 프로그래밍을 배우고 싶은 사람들을 위한 최상의 코딩 교육 프로그램을 제공합니다. 자바스크립트 HTML CSS를 기초로 탄탄한 이론과 실무에 최적화된 기술 스택들을 학습합니다. 주입식이 아닌 자기주도적 학습 방식으로 기존과는 차별화된 혁신적인 교육 시스템을 경험해보세요.goo.gl4. 유다시티유다시티는 가격대는 있지만 탄탄하고 검증된 커리큘럼의 온라인 학습 사이트다. 프로젝트 베이스에 과제도 탄탄하고 동영상 학습 중간중간 텍스트 자료와 퀴즈까지 적절하게 섞여 있어서 충분히 제값을 한다. 다른 온라인 학습 사이트에 비해 가격대가 있지만 그만큼 퀄리티는 훌륭하다. 가장 핫한 트렌드의 기술들도 배울 수 있고 난이도도 초급부터 고급까지 다양한 과정들이 있다.유다시티에서는 학습하기가 굉장히 편하다. 학습 시간을 적절히 쪼개서 부담 없이 학습이 가능하고 자료 또한 탄탄하다는 것이 장점! 하지만 역시 온라인 학습치고 가격은 부담이 된다.Udacity - Free Online Classes & Nanodegrees | UdacityJoin Udacity to learn the latest in Deep Learning, Machine Learning, Web Development & more, with Nanodegree programs & free online courses.www.udacity.com5. 인프런영어가 유데미가 있다면 한국어는 인프런이 있다! 다양한 수준의 프로그래밍 강의를 한국어로 들을 수 있는 온라인 학습 사이트다. 탄탄한 커리큘럼에 강좌 구성까지. 필요한 강의를 골라 들을 수 있다는 장점이 있다. 한국어 강좌다 보니 강사들과의 소통도 원활하다. 영어가 아직은 부담스럽다면 인프런에서 먼저 시작해보자!퀄리티 높은 무료 강좌도 존재하니 처음에는 무료 강좌들을 보면서 나에게 맞는지 확인해 보고 학습을 시작하면 된다. 단점은 유데미 보다는 가격이 비싸다는 점! 하지만 한국어 강의가 많다는 것 자체가 엄청난 장점이라 할 수 있겠다.인프런 - IT, 개발의 좋은 지식을 공유합니다개발, CG, 디자인 등 IT 분야의 고급 지식들을 편하고 경제적으로 학습할수 있는 공간입니다. 배우는 사람에겐 기회를, 지식공유자에겐 보상을 주는 문화를 만들어요.www.inflearn.com코딩 관련 질문을 하고 싶다면스택오버플로우(stackoverflow)스택오버플로우는 개발과 관련된 질문과 답변을 하는 사이트다. 코딩을 하다가 중간에 막혔는가? 괜찮다. 당신의 문제는 이미 선배 개발자들도 했던 고민이니 말이다. 스택오버플로우에서 how to 라는 말과 함께 당신이 궁금한 점을 물어보라 마법과 같은 일이 펼쳐질 것이다. 당신이 알고 싶어 하는 거의 모든 개발 관련된 문제들에 대한 답이 이곳에 있다.영어라서 부담스러워하지 말고 익숙해져보라. 스택오버플로우만 잘 이용해도 현재 당신이 안고 있는 개발 문제의 대부분이 해결될 것이다. 단, 이곳에서의 코드를 너무 복붙 했다가는 오히려 실력 저하가 온다는 것을 명심하기를...Stack Overflow - Where Developers Learn, Share, & Build CareersStack Overflow | The World’s Largest Online Community for Developersstackoverflow.com블로그&커뮤니티JS서울js서울은 자바스크립트에 대해 넓고 얕은 지식을 서울 사용자들에게 보급하려는 지역기반 커뮤니티다. 슬랙방을 만들어서 운영되고 있으며 자바스크립트를 이용하는 이용자라면 활동을 해보면 좋을 것이다.seoul.jsMeetups 2017.08.18(1st) Meeting Notes 2017.07.10 2017.07.19(kickoff) 2017.10.11(conference Staff Offline Meeting 1st) 2017.10.31(conference Staff Online Meeting 1) Seoul.js About Code Of Conduct Sponsors Why We Started Seoul.js Logo Call For Speaker Plan 2018 이제 폭넓게 사용되는 자바스크립트의 매력과 인사이트를 대한민국, 서울에seoul.js.orgOkky개발자들의 커뮤니티, 페이스북이 아니라 다른 페이지를 만들어서 활동하고 있는 개발 커뮤니티 중 가장 큰 규모가 아닌가 생각한다. 개발 관련된 질문도 하고 개발자와 관련된 생활, 진로, 일상들을 이야기하는 개발자 커뮤니티다. 질문을 올리면 선배 개발자들의 따끔한 조언을 얻을 수 있다.OKKY - All That DeveloperEditor's Choice 실리콘밸리를 그리다 - 24. 애자일 방법론으로 프로젝트 진행하기 Karen 10k 6일 전 [OKKY 세미나] 대용량 서비스 성능 개선 노하우 Karen 10k 6일 전 'IT업계 포괄임금제 미적용 특례지정'을 요청합니다. Good Luck 484 8일 전 [OKKY 취준 세미나] 국비 지원 학원 선택의 노하우와 효과적 학습법에 대하여 형 439 13일 전 OKKY 스팸 단어로 인한 글 등록 불가 문제 관련 공지사항 OKKY 475 29일 전 Q&A 자동로그인 코드 구현 할okky.kr조대협님 블로그이미 알만한 사람은 다 안다는 조대협님의 블로그. 개발자 블로깅은 이렇게 하느거야라는 정수를 느낄 수 있고 실제 유익한 정보들이 많이 올라온다. 유명한 개발자 블로거들이 많지만 나열하자면 지면이 길어지기에 대표적인 조대협님의 블로그를 추천한다. 개발 관련된 글, 정보를 얻고 싶다면 이곳에 들어가 보라!조대협의 블로그평범하게 살고 싶은 월급쟁이 기술적인 토론 환영합니다.같이 이야기 하고 싶으시면 부담 말고 연락주세요:이메일-bwcho75골뱅이지메일 닷컴.bcho.tistory.com

기업문화 엿볼 때, 더팀스

로그인

/