스토리 홈

인터뷰

피드

뉴스

조회수 1446

3월에 다녀온 여름나라 코타키나발루 3박5일 이야기 (3)

 패션블로그 웹뜰입니다어느새 웹뜰 10주년 워크샵을 다녀온지 한달이란 시간이 지나버렸네요 3월에 다녀온 여름나라 코타키나발루 3박5일 웹뜰 해외워크샵 마지막 이야기를 들고 왔습니다. 둘째날 워크샵을 마치고 세번째날은 오전에는 호텔에서의 자유시간이였습니다. 전날 워크샵으로 늦게까지 달린 웹뜰 직원들이 충분히 휴식을 취할 수 있는 시간이였어요 늦잠도 좋지만 일단 조식은 챙겨서 먹어야 하니깐 일어나 조식뷔페로 갔습니다. ㅎㅎㅎ 역시 어제 달려서인지 어제보다 많은 직원들이 보이지 않네요 식사를 하면서 수영장쪽을 보내 오늘도 날씨가 끝내줍니다. 정말이지 코타키나발루에서 계속 날씨가 좋았던거 같아요 웹뜰의 직원들의 워크샵이라 날씨운이 따라 준 것 같습니다. 날씨도 좋고 수영장도 예쁘고 자유시간이니 조식을 먹고 수영을 해보기로 합니다. :)조식을 먹고 배도 부르겠다 산책 겸 마젤란수트라하버리조트를 돌아 다녀봤습니다. 정말 안 예쁜 곳이 없는 마젤란수트라하버네요 구석구석 어디가도 인생샷스팟!여기저기 돌아다니며 사진찍고 놀다가 다시 리조트 방으로 돌아가서 수영복 갈아입고 수영장으로나왔습니다. 파란하늘에 파란 수영장 물 꺄!! 너무너무 예쁘네요 야자수까지 있으니 이국적인 느낌 물씬 수영장에선 역시 썬베드죠 ㅋㅋㅋ 수영보다 썬베드 썬베드에서 요렇게 요렇게 다들 아시죠? 요 허세샷 다들 찍어보셨을꺼예요 ㅎㅎ 수영장에서 수영도 하고 인생샷도 찍어보고 즐거운 오전시간을 보냈습니다. 마젤란수트라하버 골드카드 혜택으로 리조트 안에서 점심도 해결할 수 있었습니다.점심은 피자또는 파스타 중에 골라서 먹을 수 있었는데요 피자도 파스타도 다 맛있었어요 샐러드와 후식으로 과일까지 나오더라구요 수영하고 먹으니 더 꿀맛! 접시를 싹싹 비웠습니다. 세번째날의 오후 일정은 반딧불 투어였습니다. 반딧불 투어는 묵고 있는 마젤란수트라하버리조트에서 버스로 한참 나가야한다고 하더라구요 호텔로비에서 단체사진 한장 남기고 버스를 타고 갔습니다. 가는 중간에 휴게소라기보단... 음 화장실을 가기위해 잠시 들린 곳이라고 하는게 더 맞을 것 같습니다. 간이 매점같은곳이 있어서 간단하게 요기를 할 수도 있었습니다. 화장실은 좀... 열악했어요 물론 비용도 지불해야하고 비용 지불도 했는데 그다지 깨끗하지는 않았더라는.. 역시 어딜 가봐도 한국이 젤 깨끗한거 같아요  ㅎㅎ제가 좋아하는 옥수수도 있어서 옥수수를 사서 다른 직원과 나누어 먹었습니다. 역시 옥수수는 꿀맛이엿습니다. 넘나 맛있어서 버스에서 냄새 풍기는지도 몰랐네요 그리고 곧 도착한 식당입니다.  이 식당 뒤쪽으로 강이 흐르고 있고 배를 탈수 있는 곳이 있는데 그곳이 바로 이따 저녁에 저희가 반딧불 투어를 할 곳이라고 합니다. 식당 안쪽 인테리어는 이런 모습.. 말레이시아는 중국의 영향을 꽤나 많이 받았다고 하더니 이 식당도 흡사 중국 식당 같은 모습이네요 지금 든든히 먹어야 반딧불투어를 할때 배고프지 않다고 합니다. 반찬의 가지수는 여러가지 나쁘지 않습니다. 다만 양념에 향신료가 너무나도 듬뿍 들어가있어 입맛에 안 맞아 저희 직원들 중 대부분은 식사를 제대로 하지 못했네요 식사를 하는 웹뜰 직원들을 위해서(?) 인지 아니면 원래 시간마다 정기 공연이 있는지는 모르겠지만 막간을 이용해서 공연을 보여주는 원주민들 나름 임팩트있게 공연을 보여주고 홀연히 떠나더라구요 ㅎㅎ식당에서 밥을 다 먹고 또 차로 10분정도 이동해서 저녁노을을 보러 갔습니다. 이름모를 해변가였는데 풀어놓은 소랑 말, 그리고 개까지... 해변에 응가를 싸놓아서 발밑을 정말 조심히 걸어야했습니다. 그래도 노을지는 해변에서 각자의 인생샷과 웹뜰 직원단체로 인생샷을 건질 수 있어 너무 좋았던 곳 이였습니다. 그리고 다시 식당쪽으로 돌아가서 반딧불투어!반딧불이는 빛에 민감하기때문에 사진은 찍지 못하였습니다. 역시 가장 아름다운 자연은 눈으로 즐기는게 가장 아름답게 즐길 수 있더라구요 숲따라 흐르는 강을 배타고 가면서 까만밤 수많은 별들 그리고 크리스마스트리처럼 반짝이던 반딧불이들까지너무나도 낭만적이였던 반딧불이 투어였습니다. 반딧불이 투어를 마치고 다시 숙소로 돌아온 웹뜰 직원들 저녁식사가 부실하여 허기졌을 직원들에게 한국에서 가지고온 컵라면과  맛있는 간식을 준비해주신 대표님 짱짱! 너무나도 감사합니다. 그리고 마무리로 조니워커블루라벨과 시원한 음료까지!셋째날 밤도 불태워 보았습니다. 그리고 넷째날 아침이 밝았습니다. 오늘은 체크아웃을 하기 전까지 자유시간으로 주어진 날각자 시내투어나 키나발루산 트레킹 그리고 마젤란수트라하버 투어 등으로 시간을 보냈습니다. 마젤란수트라하버리조트는 어제 오전에 즐겼으니 오늘은 시내투어를 해보았습니다. 시내로 가는 셔틀버스는 마젤란수트라하버리조트에서 시간마다 있었습니다. 저희는 일찍 서둘러서 조식먹고 10시차를 타는 거루~!셔틀버스는 티켓을 구매해야지 이용이 가능하구요 리조트앞 셔틀버스타는 곳에서 표를 구입할 수 있었습니다. 표는 3.2링깃으로 약 1달러정도의 금액을 내면 됩니다. 조금 기다리자 수트라하버라고 쓰여진 버스가 왔네요 저희말고도 다른 한국인 관광객과 타국의 관광객들이 버스를 많이 이용하더라구요 셔틀버스를 타고 시내로 들어가자마자 젤 처음에 보이는 이마고쇼핑몰에서 내렸습니다. 가장 최근에 지어진 력셔리한 쇼핑몰이라고하네요 약간 백화점 같은 느낌의 쇼핑몰이였어요 시원하고 깨끗하고 좋더라구요 백화점 느낌인 만큼 물건도 좋긴했지만 비싼 기분도 있어서 일단 여기저기 둘러보다가 나갔습니다. 그리고 밖으로 나와서 하염없이 시내를 걷기 시작했습니다. 물론 택시나 그랩등의 교통수단을 이용해도 되었지만 일단 코타키나발루 자체가 크고 넓은 편도 아니고 일단 걸으면서 시내를 구경하는것도 좋을것 같아서였습니다. 날씨는 덥긴했지만 그래도 한국의 한여름 40도를 육박하는 조금만 서 있어도 타 들어가는 듯한 더위는 아니였던 날이여서 걷기 좋았습니다. 걸어 다니며 여기저기 쇼핑몰도 구경하고 이국적인 풍경도 구경하는 재미가 쏠쏠햇습니다. 더워서 시원한 망고쥬스라도 사먹고 싶었는데 길에서 파는 쥬스는 안보이더라구요 어느정도 돌아다니다가 KK플라자 지하로 갔습니다. 지하에 마트에서 기념품을 사기위해서죠 여기가 한국인지 말레이시아인지 ㅋㅋ 한국말로 쓰여진 네이버추천 카야잼이라는 표시 그리고 한국어를 유창하게하는 직원덕에 쇼핑을 잘 할 수 있었습니다. 지인들에게 줄 망고젤리와 달리치약등을 사서 이제 배가 고프니 근처 현지 맛집 식당까지 다녀왔답니다. KK마트에서 거의 근처에 있는 유잇청이라는 코타키나발루 맛집입니다. 네이버에 검색해보면 나오는 맛집이라서 그런지 손님들이 대부분 한국 손님이였답니다. 가게도 넓은 편이고 회전율도 좋아서 살짝 대기하고 바로 자리에 앉을 수 있었습니다.  저희는 국수 카야토스트 그리고 사태라는 말레이시아식 꼬치구이까지! 골고루 시켰습니다. 밖에서 돌아다녀서 시원한 음료가 땡껴 콜라도 시켰구요 현지식 음식이라 향신료 듬뿍이지만 향신료에 대한 거부감 거의 없는 저희는 아주 맛있게 싹싹 먹었답니다. 마젤란수트라하버 리조트로 돌아갈때도 셔틀을 이용해도 되지만 시간이 좀 많이 남아서 택시를 타고 편하게 갔습니다. 택시가 엄청 오래된 차라 에어컨이 안나와서 좀 덥긴했네요 ㅎㅎ 이번엔 키나발루산 트레킹을 한 팀의 사진을 소개시켜드리겠습니다. 키나발루산 트레킹은 막 걸어서 트레킹을 하는 느낌이라기 보단 차를 타고 이동하는 시간이 훨씬 많아서 힘들지는 않았다고 합니다. 키나발루산으로 가는 도중 마을이 있어 시장에 들려 열대과일 구경도 하구요 코타키나발루 까지와서 열대과일중 왕자라는 별명을 지닌 두리안도 안먹어볼수 없겠죠 냄새는 썩은 양파냄새 가 나서 냄새만 맡으면 못먹을 것 같았지만 의외로(?) 너무 맛있어서 다들 잘 먹었답니다. 특히 여직원들이 더 잘먹었다는 소리가 ㅎㅎ 산으로 가는 길에 만난 시원하게 흐르는 계곡물 날이 더워서 계곡물에 풍덩하고 싶은 심정을 뒤로하고 다시 키나발루 산으로 갑니다!가는 길에 히비스커스 꽃도 만났습니다. 히비스커스 꽃 말로만 듣고 말린걸 차로만 마셔봤지 이렇게 눈으로 보는건 다들 처음약간은 무궁화를 닮은 붉은 꽃잎이 너무나도 매력적인 꽃이였답니다. 그리고 울창한 열대 우림까지! 역시 자연이 젤 아름답고 위대한 것 같습니다. 키나발루 산에 올라오지 않았다면 이런 광경을 어디서 볼 수 있었을까요 키니발루산 캐노피 흔들다리도 건넜습니다. 총 4번정도 건너는 거 같은데 흔들흔들요거 은근히 덜덜 떨리더라구요 무서워서 아래를 보지도 못하고 앞만 보고 건넜답니다.  이렇게 자연풍경에 빠져서 길을 열심히 걷는 사이에 키나발루산 정상이 눈앞에 똭~!! 구름위로 보이는 산 정상에 다들 입이 똭~!!어찌나 아름다운 풍경인지 자연은 정말 위대하네요 동남아시아의 최고 높은 산이라고 들었던거 같습니다. 정상까지 갔다오려면 1박2일이 걸린다고 하더라구요 일부러 키나발루산 트레킹을 하려고 오는분들도 있다고 합니다. 저희는 정상까지는 가지 못하고 여기서 기념촬영을 하고 이제 다시 숙소로 돌아갔습니다. 시내투어팀도 키나발루산 트래킹 팀도 모두 숙소에서 잠깐의 휴식을 취하고 이제 짐을 모두 가지고 오후 6시 퇴실을 합니다. 원래 마젤란수트라 하버 퇴실시간은 11시인가 그랬던거 같은데 저희는 골드카드 혜택으로 레이트체크아웃이 가능해서 6시까지 일정을 즐기고 조금이라도 쉬다가 나올수 있어 좋더라구요 퇴실하고 시내에 나와서 야시장 구경을 하는 시간이 주어졌습니다. 야시장에서 가이드님께서 1링깃짜리 코코넛주스나 망고주스를 사주었습니다. 기대하고 먹었는데 시럽이 좀 섞여있는 맛 ㅎㅎㅎ100% 과즙은 아니라 조금 실망했지만 그래도 나름 맛있게 잘 마셨습니다. 이따 몇 시까지 어디로 모이라고 말한 뒤 이제 각자 야시장 구경 오전에 나왔을때의 시내와는 좀 다른 모습이네요 오전은 더워서 였을까요? 오전엔 사람이 많이 보이지 않았는데 오후가 되니 사람들도 많이 보이고 여러가지 장사들이 나와서 인지 좀 더 활기 띈 모습이였습니다. 그래도 위험할 수 있기 때문에 절대 혼자는 다니지 말고 가방은 꼭 앞으로 매고 다녀야 한다고 가이드님께서 신신당부하였답니다. 야시장의 꽃은 역시 열대 과일이죠 ㅎㅎㅎ맛보라고 맛만 보라고 자꾸 말하는 동남아 상인들맛보고 어떻게 안 사냐구요! 저희 밥 먹구 공항가야해서 과일은 못사요 쏘리~야시장구경은 근처의 수공예시장도 구경해봅니다. 우리나라 남대문이나 동대문 시장 정도 되는 느낌의 가게가 빼곡히 자리 잡고 있었구요 여기가 기념품 사기에는 야시장보다 좀 더 볼거리도 많았습니다. 다만 너무너무너무너~~~무 더워서 오래 있지는 못하고 후딱후딱 보고 딱 사야 할 것만 사가지고 나왔네요 저는 여기서 지인에게 줄 드림캐쳐를 샀답니다. 물론 공항에서도 팔지만 여기서는 흥정도 가능하고 더 싸게 살수 있었습니다 :D야시장 구경이 모두 끝나고 이제 저녁먹을 시간 만나는 장소로 다들 시간 맞춰서 잘 와서 식당으로 이동! 무브무브코타키나발루에서의 마지막 저녁식사는 씨푸드였습니다. 뭐 씨푸드 하면 다들 떠올리는 바닷가재 킹크랩 왕새우등의 요리는 아니였지만 생선과 생선탕수, 크림새우, 오징어튀김등 그래도 씨푸드는 맞았네요 마지막 식사이니 만큼 다들 맛있게 잘 먹었답니다. 그렇게 식사를 모두 마치고 이제 공항으로 이동!3박5일간의 짧고도 긴 여행이 끝이났네요 워크샵으로 코타키나발루를 다녀오게 되다니 정말 웹뜰 직원이여서 행복하고 즐거운 시간들이였답니다. 다녀와서 힐링의 시간이 되었던거 같아요 함께한 10년보다 함께할 10년에 더욱 기대감을 가지며 일할 수 있을 것 같습니다. 담번에 또 즐겁고 재밌는 소식으로 찾아뵐께요 웹뜰의 워크샵 첫번째 이야기와 두번째 이야기는 아래 참고하시면 됩니다:)[웹뜰 창립 10주년 해외워크샵] 3월에 다녀온 여름나라 코타키나발루 3박5일 이야기 (1)[웹뜰 창립 10주년 해외워크샵] 3월에 다녀온 여름나라 코타키나발루 3박5일 이야기 (2)#코타키나발루 #워크샵 #해외워크샵 #웹뜰 #웹뜰워크샵 #마젤란수트라하버 #키나발루산 #인천공항 #이스타항공 #시내투어
조회수 1048

컴공생의 AI 스쿨 필기 노트 ⑥인공신경망

인공지능, 머신러닝, 딥러닝이번 6주차 AI 스쿨에서는 딥러닝의 가장 기초적인 부분을 배웠어요. 인공지능과 머신러닝, 그리고 딥러닝을 많이 들어보긴 했는데 이 셋의 차이는 무엇일까요?인공지능이라는 개념은 1956년 미국 다트머스 대학에 있던 존 매카시 교수가 개최한 다트머스 회의에서 처음 등장했고 최근 몇 년 사이 폭발적으로 성장하고 있는 중이에요. 1956년 당시 인공지능의 선구자들이 꿈꾼 것은 최종적으로 '인간의 지능과 유사한 특성을 가진 복잡한 컴퓨터'를 제작하는 것이었죠. 이렇듯 인간의 감각, 사고력을 지닌 채 인간처럼 생각하는 것을 인공지능이라고 해요.인공지능은 위 세 개념 중 가장 큰 개념이에요. 머신러닝은 일반적으로 사람들이 이야기하는 인공지능, 즉 머신러닝에 기반한 인공지능을 말하는데요. 인공지능을 구현하는 구체적인 접근 방식이라고 할 수 있어요.머신러닝에는 linear regression, logistic regression 등의 여러 알고리즘이 있는데요.  그중 학습에 사용되는 모델을 딥러닝이라고 해요. 즉 딥러닝은 완전한 머신러닝을 실현하는 기능이라고 볼 수 있어요. 이러한 딥러닝의 등장으로 인해 머신러닝의 실용성은 강화됐고 인공지능의 영역은 확장됐다고 해요.인공 신경망(Neural Network)오늘 수업의 핵심인 인공 신경망(Neural Network)은 어떻게 만들어졌을까요?뉴런의 구조이것은 우리 몸에 존재하는 신경세포인 뉴런이에요. 뉴런은 전기적인 신호를 전달하는 특이한 세포인데 뇌는 뉴런의 집합체라고 할 수 있어요. 뉴런은 수상 돌기(dendrites, input)에서 신호를 받아들이고 축색 돌기(axon terminals, output)에서 신호를 전송해요. 신호가 전달되기 위해서는 일정 기준(임곗값 : threshold) 이상의 전기 신호가 존재해야 해요. 이 신호들의 전달을 통해서 정보를 전송하고 저장해요.이런 신경세포로 이뤄진 신경망 시스템을 위의 그림처럼 표현할 수 있어요. 이처럼 인공신경망은 사람 몸속의 신경들을 모방해서 만든 시스템이에요.위의 식처럼 뉴런을 수학적으로 표현할 수 있는데요. 입력 값들(X)에 가중치를 두어(W) 값 (f(x))을 구하고 그 값과 임계치와의 관계를 활성함수(active function)*로 판단하여 결괏값을 출력하게 돼요.( * 활성함수는 인공신경망의 개별 뉴런에 들어오는 입력신호의 총합을 출력 신호로 변환하는 함수로 비선형 함수(non-linear function)를 씁니다.**)이때 활성함수는 뉴런에서 임곗값을 넘었을 때만 출력하는 부분을 표현한 것으로 sigmoid 함수, Relu 함수 등 여러 방식이 있어요.인공 신경망의 구조인공 신경망 구조는 위의 그림처럼 나타낼 수 있어요. 인공 신경망 구조는 입력층(input layer), 은닉층(hidden layer), 출력층(output layer)으로 이루어져 있어요. 위의 그림은 그 구조에 의해 3-layer Neural Network 또는 2-hidden-layer Neural Network라 부를 수 있는데요. 3-layer Neural Network는 3개의 층을 가지는 인공신경망이라는 뜻이고, 위 그림에서는 은닉층1, 은닉층2, 출력층이 해당되겠죠. 인공 신경망에 입력층과 출력층은 항상 존재하기 때문에 은닉층의 개수만을 고려하여 부르기도 해요. 위 그림에서는 은닉층이 2개 있기 때문에 2-hidden-layer Neural Network라고 부를 수 있어요. 전파(Propagation)이번에는 실제로 학습하는 과정인 인공신경망의 알고리즘에 대해 알아볼게요. 순전파(Forward Propagation)와 역전파(Backward Propagation)가 있어요.순전파는 입력값에서 출력값으로 가중치를 업데이트를 하고 활성화 함수를 통해서 결괏값을 가져오는 것을 말해요. 인공신경망이 설계된 정방향(input → hidden → output)으로 데이터가 흘러가기 때문에 순전파라고 해요. 말 그대로 입력값을 앞쪽으로 보낸다고 생각하면 돼요.역전파는 출력값을 통해서 역으로 입력값 방향으로 오차를 다시 보내며 가중치를 재 업데이트하는 것이에요. 출력값에서 계산된 오차에 가중치를 사용해 바로 이전 층의 뉴런들이 얼마나 오차에 영향을 미쳤는지 계산해요. 결과에 영향을 많이 미친 뉴런일수록 더 많은 오차를 돌려줘요.개념을 코드에 적용하기NumPy로 구현된 Neural Network(이하 NN)의 작동 방법을 살펴볼게요. NN은 총 2개의 레이어로 이루어져 있어요. 이번 과제에서는 입력 x가 들어왔을 때, 레이블에 따라 예측치가 1로 수렴하는지 알 수 있는 인공신경망을 구현하는 것이 목적이에요.Neural Network다음 코드는 simpleNueralNet() 클래스를 나타내는 코드예요. simpleNueralNet()은 두 개의 레이어로 구성된 NN이에요.N, D_in, H, D_out = 64, 1000, 100, 10- N은 batch size, 즉 한 번에 처리할 수 있는 데이터 사이즈를 말해요. - D_in은 입력값 차원에 쓰이는 값으로 1000을 할당해요.- H는 은닉층 차원에 쓰이는 값으로 100을 할당해요.- D_out은 출력값 차원에 쓰이는 값으로 10을 할당해요.아래 코드를 통해서 랜덤 입력과 출력 데이터를 만들어요.x = np.zeros((N, D_in))     #1  x.fill(0.025)                         #2y = np.ones((N, D_out))   #31. np.zeros() 함수를 사용하여 (64, 1000)의 차원을 갖는 0인 행렬을 만들어요.2. fill() 함수를 통해 x 안의 모든 0을 0.025로 바꿔요.3. np.zeros() 함수를 사용해 (64, 10)의 차원을 갖는 0인 행렬을 만들어요.아래는 랜덤 값을 갖는 가중치(weight)들을 초기화하는 코드예요. w1은 1000, 100 차원의 랜덤 값을 갖는 행렬로, w2는 100, 10차원의 랜덤 값을 갖는 행렬로 만들어요.w1 = np.random.randn(D_in, H)   w2 = np.random.randn(H, D_out)learning_rate는 학습 속도를 의미해요. 아래는 단계별로 움직이는 학습 속도를 1e-6으로 정의하는 코드예요.learning_rate = 1e-6이제 5000번의 순전파를 할 거예요.h = x.dot(w1)     h_relu = relu(h)  y_pred = h_relu.dot(w2)h는 은닉층에 전달할 값이에요. x와 w1을 행렬곱한 값을 가져요.활성 함수 relu에 h를 넣어서 계산해요.y_pred는 예상되는 출력값이에요. relu로 계산된 h_relu와 가중치 w2를 행렬곱한 값이에요.아래는 순전파로 얻은 y_pred에서 진짜 y를 뺀 값을 제곱한 것의 합을 구해 손실 값(loss)을 구하는 코드예요. print(loss) 코드로 손실을 확인할 수 있어요.loss = np.square(y_pred - y).sum()순전파 후 역전파를 이용해 손실에 대한 가중치 w1과 w2의 gradients를 계산하여 update 할 거예요.grad_y_pred = 2.0 * (y_pred - y)              #1grad_w2 = h_relu.T.dot(grad_y_pred)    #2grad_h_relu = grad_y_pred.dot(w2.T)    #3grad_h = grad_h_relu.copy()                    #4grad_h[h < 0>grad_w1 = x.T.dot(grad_h)                         #61. 순전파로 얻은 y_pred에서 진짜 y값을 뺀 값에 2.0을 곱하여 grad_y_pred를 구해요.2. grad_w2는 순전파에서 y_pred = h_relu.dot(w2) 식을 사용했으므로  h_relu.T.dot(grad_y_pred) 로 구해요. h_relu가 반대로 곱해지기 때문에 T를 이용하여 shape을 바꿔줘야 해요.3. grad_h_relu는 방금 위에서 사용한 y_pred = h_relu.dot(w2)을 이용하여 grad_y_pred.dot(w2.T) 로 구해요. 이번에는 w2 shape의 반대를 grad_y_pred에 곱해줘야 해요.4. 순전파에서 h_relu = relu(h)였는데요. 역전파에선 grad_h와 grad_h_relu가 같기 때문에 copy() 함수로 그대로 복사해요!5. 0보다 작은 h는 0으로 만들어요.6. 가중치 w1의 값인 grad_w1은 순전파의 h = x.dot(w1)와 반대로 x.T.doT(grad_h) 곱해요. 역전파는 순전파의 식에서 이항한다고 생각하면 조금 더 쉽게 이해할 수 있을 것 같아요. 이항한 값은 .T를 붙여서 표현한다고 생각하면 될 것 같아요.아래는 가중치를 재업데이트하는 코드예요.w1 -= learning_rate * grad_w1 w2 -= learning_rate * grad_w2 과제1을 통하여 NN을 알아보았는데요. 복잡하지만 순전파와 역전파를 알고 있다면 많이 어렵지는 않은 것 같아요. 과제 2는 정확도를 95% 이상으로 만들어보는 과제인데 여러 가지 방법을 동원해서 풀어보는데 생각보다 쉽지가 않아요. ^^;이번 수업시간에 배운 딥러닝의 기초인 신경망은 굉장히 중요한 개념이라고 해요. 신경망을 기반으로 한 딥러닝을 강화하여 안면인식을 가능하게 하거나 저장된 데이터를 정확하게 인식하고 분류할 수 있는 기기들도 만들어지고 있어요. 이처럼 AI는 점진적으로 활용 범위가 넓어지고 있기 때문에 이 수업을 통해 쌓은 AI 지식을 마음껏 뽐낼 수 있는 날이 왔으면 좋겠어요!** 왜 활성함수로 비선형 함수를 쓸까요?선형함수인 h(x)=cx를 활성함수로 사용한 3-layer 네트워크를 생각해봐요. 이를 식으로 나타내면 y(x) = h(h(h(x)))가 되는데요.  이는 y(x) = c3x와 같습니다.  이렇게 활성함수로 선형함수를 사용하면 은닉층을 사용하는 이점이 없어요.* 이 글은 AI스쿨 - 인공지능 R&D 실무자 양성과정 6주차 수업에 대해 수강생 최유진님이 작성하신 수업 후기입니다.
조회수 2820

리디북스 웹뷰어의 이어보기를 개발하며

최근 리디북스에서는 판타지 연재물을 웹에서 바로 볼 수 있는 기능을 새롭게 선보였습니다.기존에는 별도의 앱을 설치하고 다운로드하는 과정을 거쳐야 했기에 연재물을 보는 사용성이 좋지 않았습니다만, 브라우저에서 바로 볼 수 있는 “웹뷰어” 기능을 제공함으로써 사용성을 높일 수 있었습니다.그리고 여기에 사용성을 더하기 위해 추가된 것이 이어보기 기능입니다. 짧아도 100화 이상, 길게는 1000화가 넘는 연재물에서 다음 화로의 매끄러운 연결은 매우 중요합니다. 혹은 잠시 읽기를 중단했다가 다시 돌아왔을 때, 어디까지 보고 있었는지를 빠르게 알려준다면 호흡을 이어서 작품에 더욱 몰입할 수 있을 것입니다.이어보기가 구현된 모습리디북스에 로그인되어 있다면, 이곳에서 확인하실 수 있습니다.이번 글은 이어보기 기능에 대한 개발 후기입니다. 요구 사항에 따라 여러 저장소 솔루션을 비교해 보았으며 최종적으로 Couchbase를 선택한 이유와 간단한 벤치마크 결과, 그리고 겪었던 문제를 공유합니다.요구 사항기획된 내용을 요약하니 아래와 같습니다.연재물의 가장 마지막에 읽은 화를 알 수 있다.보았던 모든 연재물에서 가장 마지막에 읽은 연재물을 알 수 있다.사용자가 본 모든 연재물 목록을 확인할 수 있다.이를 개발자 용어로 다시 풀어보면 아래와 같습니다.연재물을 읽을 때마다 연재물 ID와 화(episode) 정보를 기록한다.보았던 연재물을 최신순으로 정렬하여 가져온다.선택된 연재물의 마지막으로 읽은 화를 가져온다.목록에서 특정 연재물을 삭제한다.이어보기는 가장 마지막에 읽은 연재물을 기억하기 위해 작품을 열 때마다 해당 정보를 기록해야 합니다. 그런데 수십 화를 연달아서 보는 연재물의 특성상 내가 어디까지 읽었는지를 조회하는 것(read)보다 내가 읽은 연재물을 기록하는 것(write)이 더 많을 것으로 판단했습니다. 즉, 읽기보다 쓰기가 더 많을 것으로 예상했습니다.NoSQL을 쓰자대부분의 연산이 쓰기(write)와 관련된 이상, 어떤 저장공간을 사용할 것인지가 주된 관심사였습니다.특히 RDBMS와 NoSQL 사이에서 어떤 것을 사용할지 많은 고민과 테스트를 했고, 결국 아래와 같은 이유로 NoSQL을 사용하는 것이 적합하다고 판단했습니다.현재 사용 중인 MariaDB를 그대로 사용한다면 마스터에 부담을 줄 수 있다.별도로 MariaDB를 구성하더라도 운영 및 쓰기 분산하기가 여전히 어렵다.반면 NoSQL은 RDBMS 대비 확장(Scale out)이 간편하므로 운영에 대한 부담이 적다.단순 Key-Value 보관 용도면 충분하다.이어보기 데이터는 독립적인 성격을 가지고 있어서 다른 사용자 데이터와 JOIN을 할 필요가 없다.이어보기 데이터는 크리티컬한 트랜잭션이 필요하지 않다.MongoDB vs. Couchbase데이터를 영속적으로 유지해야 한다는 요구 사항을 충족하기 위해, Redis 등의 메모리만 사용하는 NoSQL은 제외했습니다. 물론 디스크에 기록할 수 있지만, 성능이 급감하기 때문에 실용적이지 못 합니다. 또한, 메모리 사이즈에 기반을 두기 때문에 Scale up 비용이 크고, 서비스 확장시 Scale out 빈도가 높습니다.그래서 MongoDB와 Couchbase를 비교 대상으로 했습니다. 둘 다 도큐먼트 기반의 NoSQL이고 확장이 용이합니다. 과거에는 MongoDB가 Write lock 사용에 있어서 문제점이 있었지만, 최근 버전에서는 문제가 되지 않습니다.[1] 둘 다 기업용 서비스 및 충분한 부가 기능들을 제공하므로 선택하기 어려웠지만, 최종적으로 아래와 같은 이유로 Couchbase(CE)를 선택했습니다.1. 이미 사내에서 다른 서비스에 사용되고 있습니다.가장 중요한 요인이었습니다. 더 좋은 솔루션이 있더라도 어디까지나 서버 스택을 늘리는 것 이상의 효용이 있는지를 따져보아야 합니다. 이미 사용하고 있는 솔루션이 있다면, 검증이 되었을 뿐만 아니라 개발 및 운영 경험도 활용할 수 있습니다.2. 이어보기는 복잡한 쿼리(Query)가 필요 없습니다.이어보기에서 사용할 쿼리는 간단하기 때문에 Couchbase의 뷰(View)만으로 충분했습니다.Couchbase, 실제 성능은 어떨까?테스트를 하기 전 우리가 어떤 식으로 사용할 것인지 정리해야 합니다. 애플리케이션 액세스 패턴이나 동시성 문제, 데이터 구조화 등을 파악하고 그에 맞는 테스트를 진행해야 합니다. 이번 이어보기는 쓰기 연산이 보다 많기 때문에 이로 인한 뷰의 인덱싱(Indexing)에 초점을 맞추고 테스트를 진행했습니다.성능을 위협하는 요소들View IndexingCouchbase는 MapReduce를 이용하여 뷰를 제공합니다. MapReduce는 일반적으로 리소스를 많이 소모하는 동작입니다. 그래서 Couchbase는 버킷의 새로 갱신된 데이터만 인덱싱하는 Incremental MapReduce라는 기법을 적용해서 리소스 소모를 줄였다고 합니다.[2] 하지만 해당 작업으로 인한 부하는 여전히 발생합니다.Auto CompactionCouchbase는 데이터와 인덱스를 디스크에 데이터를 저장할 때 파일에 추가하기(Append) 모드로만 쓰기를 수행합니다.[3] 그리고 오래되고 불필요한 데이터들은 추후 한꺼번에 정리하는데, 이는 디스크 쓰기 성능을 최대화하기 위함입니다.그런데 이렇게 추가만 하게 되면 오래된 정보들은 파일의 앞에 쌓이게 됩니다. 그리고 사용하지 않게 된 데이터도 남아있습니다. 이를 주기적으로 정리해서 최적화하는 작업을 Auto Compaction이라고 합니다. 뷰의 인덱스는 디스크에 존재하기 때문에 디스크 작업이 있으면 인덱싱에 영향을 미치게 됩니다.성능 테스트Couchbase는 기본적으로 5,000ms마다 Index를 업데이트합니다.[2] 그리고 데이터를 비동기적으로 응답합니다. 비동기는 응답속도를 빠르게 하지만, 데이터 불일치가 발생할 수 있습니다. 데이터 불일치가 신경 쓰이고 이 시간이 길다고 생각되면, stale 옵션을 지정해서 뷰의 인덱스를 업데이트할 수 있습니다.이어보기는 뷰가 간단하기 때문에 응답시간에 큰 문제가 없을 것으로 예상하고 stale 옵션을 꺼두었습니다. 이 옵션은 뷰를 조회했을 때 버킷의 변경사항에 따라 뷰를 인덱싱하고 데이터를 응답합니다. 하지만 예상한 것과 같이 실제로도 응답시간이 짧은지 확인할 필요가 있습니다. 그래서 다음과 같이 테스트를 진행했습니다.테스트 환경은 아래와 같이 2-tier로 준비하고 요청을 늘려가면서 RPS를 측정했습니다.서버 구성OS: Ubuntu 14.04Application: Couchbase Server (CE) 3.1.3클라이언트 구성클라이언트 1개에서 50개의 세션으로 요청10만 사용자 가정책은 1만개의 책중 랜덤으로 선택됨요청의 70%는 책 읽기(Bucket Write)요청의 30%는 연재물의 마지막에 읽은 책 가져오기(View Read)그래프 분석성능 테스트 주요 지표RPS : Response Per SecondSP : Saturation PointBuckle zone : 시스템 과부하로 인해 내부 자원이 서로 경쟁상태나 적체 상태가 심해지기 때문에 최대 처리량보다 더 떨어지는 경우가 발생함성능테스트 결과그래프를 보면 요청이 늘어남에 따라 RPS가 선형으로 증가하지만, SP인 8,000 RPS에 도달하고 나서 Buckle zone에서 7,000 RPS로 수렴하고 있습니다. 물론 1개의 클라이언트에서 세션을 생성해서 테스트를 진행했기 때문에 서버의 성능 부족이 아닌 클라이언트의 병목 현상이 원인일 수 있습니다. 또한 JMeter나 다른 부하 테스트 툴을 사용하지 않고 간략하게 만든 테스트 툴을 사용하였기 때문에 수치가 부정확할 수 있습니다. 그러나 어디에서 병목이 있었든 현재 이 이상의 성능이 필요하지 않기 때문에 테스트 결과에 만족할 수 있었습니다.이어보기 배포 후모바일 브라우저 캐시 문제이어보기 기능을 배포하자마자 당일 저녁 이슈 하나를 접수했습니다. 아이패드와 PC를 번갈아 이용할 경우 이어보기 데이터가 맞지 않다는 것이었습니다.데이터를 쌓을 때 모든 이력을 기록하지는 않았지만, 다행히도 Couchbase에 이용기기와 시간은 기록하였기 때문에 이를 바탕으로 디버깅을 할 수 있었습니다. (서비스 초기라 할지라도 최대한 많은 이력을 남기는 것이 중요함을 다시 느꼈습니다)원인은 아이패드의 멀티태스킹으로 인한 캐시 소멸이었습니다. 아이패드 브라우저의 캐시가 소멸되면서 마지막으로 열어두었던 페이지가 강제적으로 리로딩되었고, 이때 의도치 않게 마지막 위치 정보가 덮어씌워진 것입니다.이 문제는 기술적으로 해결이 쉽지 않아 결국 기획을 수정하게 되었습니다. 사용자가 해당 책을 읽었다고 판단하는 기준이 “페이지를 열어본 즉시”였다면, 이를 “페이지를 열고 수 초 이상을 유지”하는 것으로 기준을 변경하였습니다. 물론 근본적인 해결책은 아니었지만, 실제 사용에는 지장이 없는 합리적인 해결책이라고 생각합니다.Key 구조의 변경 및 동시성 문제Couchbase는 높은 성능을 위해 메타데이터(Key + @)를 모두 메모리에 적재하는 특징이 있어서, Document 하나가 평균 350Byte를 차지하고 있었습니다. 따라서 현재 상태로 1000만개의 데이터를 저장할 경우 최소 3.5G의 메모리를, 2개의 사본(Replica)를 유지할 경우 약 10.5G의 메모리를 사용하게 될 것으로 예상되었고 이는 큰 부담으로 다가왔습니다.처음에는 단순히 “사용자ID_연재물ID” 형태의 Key를 사용하였지만, 보다 빠르게 증가할 것으로 예상되는 것은 사용자보다 연재물 이었으므로 아래와 같이 Key값을 변경하여 메모리 사용량을 크게 줄였습니다.// U_id : S_id 조합을 사용하면 Key가 엄청 많아진다. // 그래서 사용자당 Key를 100개로 제한하도록 한다. Count = 100 Key = '사용자ID' + ('연재물ID' % Count) 그런데 이렇게 Key 구조를 변경하였더니, 간단한 업데이트 동작임에도 불구하고 정상적으로 수행되지 않는 경우가 빈번하게 발생하였습니다. 이유는 낙관적 동시성(Optimistic concurrency) 모델의 특징 때문이었는데, Couchbase는 명시적인 잠금 이외에도 “Check and Set(CAS)”이라는 기능을 제공하고 있었습니다.공식 문서의 예제를 참고하여 아래와 같이 로직을 수정한 뒤로는 다행히도 동시성 문제가 아직까지 발생하지 않고 있습니다.boolean updateUsingCas(key, value) {  for (tryCount = 0; tryCount < MAX>    orgValue, cas = getValueAndCas(key)           // Update the original value.     // newValue = ... if setValueWithCas(key, newValue, cas)      return SUCCESS sleep(0.1) // 부하를 줄이기 위해  }  return FAIL } 맺으며동작하는 서비스에 새로운 기능을 추가한다는 것은 어려운 일입니다. 특히 새로운 데이터 스토리지를 필요로 하는 일이라면 더더욱 어렵다고 생각합니다. 그리고 그럴 때일수록 설계에 많은 시간을 들여야 한다는 것을 느꼈습니다. 설계 초기에는 RDBMS의 샤딩까지 고려하였지만, 요구 사항을 구체화할수록 단순 Key-Value로도 같은 문제를 해결할 수 있음을 깨달았기 때문입니다.또한, 서비스 개발에 있어서 어려운 문제를 마주했을 때 기술적으로만 접근할 것이 아니라 고객이 정말 원하는 것이 무엇인지를 고민하여 기획적으로 해결하는 능력도 중요하다는 것을 실감하였습니다.마지막으로 Couchbase는 현재로서도 꽤 좋고 앞으로도 많은 발전이 기대되는 NoSQL입니다. 도입을 고민하시던 분들께 조금이라도 도움이 되었기를 바랍니다.참고자료[1] MongoDB - Concurrency[2] Couchbase - Views Operations[3] Couchbase - File write#리디북스 #개발 #개발자 #서버개발 #서비스개발 #고객중심 #기능개발 #Couchbase #인사이트 #개발후기
조회수 1096

알리바바에서 소싱할 때

안녕하세요 대한민국 셀러들의 성공적인 아마존 진출을 도와주는 컨설팅 회사이자 대행사인 주식회사 컨택틱의 이이삭 대표입니다.이전에는, 제조사와 거래할 때와 무역회사와 거래할 때의 장단점을 비교해봤습니다. 그렇다면 알리바바에서 소싱 할 때 제조사와 무역회사를 구분 짓는 방법이 무엇이 있을까요? 4가지만 기억하세요.1. 대놓고 물어본다너무 당연한 상식이라 이걸 보고 좀 당황스러울 수도 있다고 생각합니다. 하지만 사람은 대개 당연한 걸 무심코 넘기는 경향이 있다고 모두가 동의할 것입니다. 상대방이 제조사인지 무역회사인지, 대놓고 물어보는 게 어찌 보면 가장 깔끔하고 시원한 방법이 될 수 있습니다. 그리고 대부분의 경우, 이런 질문을 받았을 때, 망설임이나 질문을 우회하는 것 없이 직설적으로 ‘예 저희는 공장입니다’라고 답변하는 분들 중에 거짓말하는 사람은 굉장히 드물기 마련입니다. 만약 썩 시원치 않은 대답을 받을 경우, 예를 들어 ‘우리는 파트너십을 맺은 공장이 있다. 공장이나 다름없다. 맞다 우린 제조’유통’업자다.’ 등등, 일단 의심하고 보는 게 좋습니다. 수출 자격증이 있는지 물어보는 것도 아니고, 인허가 자료를 구비했는지 물어보는 것도 아니라, 단순히 제품을 직접 제조하는 제조사인지 물어봤을 뿐인데, 만약 본인이 정말 제조사 즉 공장이면 대답을 회피할 필요가 전혀 없기 때문입니다.2. 전시된 상품 라인을 검토한다이것도 사실 당연한 얘기지만, 정말 상대방이 제조사가 맞다면 상품 라인 (상품군)이 어느 정도 일관성이 있을 수밖에 없습니다. 식칼류에 특화되어있거나, 수건류에 특화되어있다거나, 이런 식으로 어느 특정 시장에 특화되어있다는 얘기이죠. 그럴 수밖에 없는 게, 한 ‘종류’의 상품을 제조하려면 그에 맞는 장비가 필요합니다. 하지만 제조에 필요한 장비 시설의 가격은 절대 만만하지 않습니다. 해당 공장이 대기업 수준으로 규모가 크지 않는 이상 한 공장에서 휴대폰 케이스도 제조하고, 베개도 제조하고, 식탁도 제조할 수는 없는 게 당연합니다.반대로, 정말 상식을 벗어난 다양한 상품군의 제품들이 알리바바 미니 몰 스토어에 전시되어있다면 해당 판매자는 공장이 아니라 무역 회사일 가능성이 매우 높습니다. 이런저런 공장과 연을 형성하고 그들의 제품들을 해당 무역회사의 알리바바 storefront에 전시해놓는 셈입니다.Photo by Hayes Potter on Unsplash3. 상품에 대한 구체적인 질문을 한다구체적인 질문을 물어보면 해당 분야에 대한 상대방의 지식수준이 여실히 드러나게 됩니다. 전문가 수준의 질문까진 필요하지 않더라도, 해당 분야에 주로 사용되는 소재나 규격, 부품, 건전지가 들어있다면 수명 시간 등에 대한 질문 및 용어를 미리 사전에 시장조사를 하면서 익히고, 상담하고 있는 상대방에게 전화나 채팅으로 실시간으로 물어봐야 합니다. 이메일로 물어보면 지식이 없던 사람도 구글링을 통해 금방 알아보고 어쨌거나 답변을 할 수는 있게 되기 때문에, 반드시 전화나 채팅으로 물어보셔야 됩니다. 그리고 질문을 받은 당사자가 즉시 대답을 하지 못하거나 당황해한다면 제조사라기보단 중간에 알선해주는 무역 회사일 가능성이 높다고 판단할 수가 있습니다.4. 직접 공장을 방문한다사실 여기까지 하는 것은 여러분께 큰 부담이 될 수 있습니다. 중국은 방문하려면 비자가 필요하고, 무엇보다 사업장을 비우고 외국 출장을 갔다 오는 것이기 때문에 시간적, 인력적, 금전적 투자가 발생하는 셈입니다. 하지만 그런 모든 것을 감수할 정도로 중요한 사안이면 당연히 방문을 하는 게 맞습니다. 그리고 방문하겠다고 했을 때 흔쾌하게 ‘OK’하는 분들은 공장을 직접 운영하는 제조사일 가능성이 높은 것은 당연합니다. 제조사 입장에서 여러분의 방문은 전혀 손해 볼 것이 없는 것이기 때문에 방문을 절대로 마다하지 않습니다. 만약 온갖 핑계를 대면서 (지방에 위치해있다, 요즘 바빠서 방문은 어렵다, 등등) 피한다면 분명히 무역회사가 본인의 돈벌이 수단이나 마찬가지인 ‘공장 인맥’을 숨기기 위함이니, 그런 분들은 무역회사라고 단정 지을 수 있습니다.Photo by Ant Rozetsky on Unsplash알리바바는 80% 정도가 무역회사라고 합니다. 20%의 실질적으로 공장을 소유하고 상품을 직접 제조하는 제조사를 찾기 위해서는 위 4가지 방법을 잘 기억해주셔서 알리바바에서 상담하실 때 요긴하게 사용하시면 금방 누가 제조사이고 누가 무역회사인지 구분할 수 있을 것입니다.컨택틱의 모든 교육은 파트너인 글로벌셀러창업연구소와 접수하고 진행합니다. 교육 신청은 아래 링크나 글로벌셀러창업연구소의 홈페이지를 통해 가능합니다.오프라인 아마존 입문 과정오프라인 아마존 기초/심화 과정온라인 아마존 입문 과정그럼 오늘도 즐거운 글로벌 셀링 되세요!감사합니다.컨택틱서울특별시 서초구 서초대로 356, 606호(서초동, 서초지웰타워)대표 전화: 02-538-3939이메일: [email protected]홈페이지: https://www.kontactic.com네이버 블로그: https://blog.naver.com/kontactic카카오 브런치: https://brunch.co.kr/@allaboutamazon유튜브 채널: https://www.youtube.com/c/kontactic
조회수 788

[인터뷰] 미국에서 아름다움을 알리는 MEMEBOX USA의 Arnold를 만나다

찌는듯한 무더위!다들 잘 견디고 계신가요!?미미박서들은 더위에도 장마에도 고객의 아름다움과새로운 경험을 위해 고민 또 고민 중이랍니다.오늘은 저 멀리 미국의 고객들의아름다움을 책임지고 있는 MEMEBOX USA의 리더Arnold의 인터뷰를 소개해드리려고 합니다!지난번에도 소개해드렸듯이 (샌프란시스코 오피스보러 가기)미국 오피스가 시작된 스토리는 참 재밌는데요!구글에서 일하던 아놀드가 6개월간 지속적인훈수(?)를 두다 결국 미미박스에 조인하게 되었죠!아놀드는 미미박서들의 성장과테크와 뷰티를 연결하는 미미박스의 비전을 실현시키는 것에 특히 중점을 두고 있다고 합니다그럼 아놀드의 이야기를 함께 만나 보실까요?  Q. 아놀드 안녕하세요. 자기소개 부탁드려요A. 안녕하세요. 제 이름은 아놀드이구요. 저는 MEMEBOX USA(클릭)의 HEAD로 미국팀을 리드하고 있어요. 스타트업, 미미박스, 치맥을 좋아해요. Q. 이렇게 이야기를 전할 수 있게 되어 좋은데요! 인터뷰에 앞서 아이스 브레이킹 질문을 하나 드리겠습니다. 누군가 아놀드에 대한 영화를 만든다면 어떤 내용일까요?A. 음 누군가 저에 대한 영화를 만든다면 예측할 수 없는 코미디 영화일 것 같아요. 예상치 못한 상황이 계속 나오지만 주인공은 스스로 즐기면서 재미와 길을 찾아가는 그런 내용이 될 것 같아요. Q. 스타트업이나 IT업계를 배경으로 한 코미디 영화가 상상돼요. 아놀드를 한 단어로 묘사할 수 있다면 어떤 단어를 선택할 것 같나요?A. 한 단어를 뽑자면 '성장'입니다. 수익 같은 성장만 이야기하는 건 아니고요. 스타트업에서 매일 새로운 상황에 도전하고 스스로 잘하는 것이 무엇인지 배우고 그러면서 성장하고 있기 때문이에요. 스타트업의 장점이자 제가 성장한다고 느낄 때는 회사에 있는 모든 동료가 당신의 성장을 돕길 원할 때죠. 또한 각자가 성공적으로 해내길 바라고요. 제 생각엔 이러한 성장이라는 단어가 제 삶과 도전을 설명한다고 생각해요.Q. 성장! 미미박스가 전사적으로 강조하고 지향하는 가치 중 하나죠. 아놀드가 미미박스에 함께 하게 된 계기는 무엇인가요?A. 우선, 산업적인 측면에서 굉장히 기대됐어요. 뷰티 산업에 테크놀로지를 접목한다는 것이 제 가슴을 뛰게 했던 것 같아요. 이런 것이 전통적인 뷰티산업엔 없잖아요. 그게 처음에 제 흥미를 사로잡았던 것 같아요.하지만 그것보다도 처음 미미박스 팀을 만났을 때, 이것은 기회라고 생각했어요. 스스로 자랑스러워하는 일을 하고, 스스로 즐기는 일을 하고, 함께 있기만 해도 즐거운 사람들과 만나서 일하는 기회는 인생에 흔치 않잖아요. 이런 좋은 기회를 놓치고 싶지 않았어요.Q. 미미박서라면 다들 공감할 것 같아요. 아놀드가 미미박스에 오기 전에는 어떤 일을 하셨는지 궁금해요A.  처음으로 일한 곳은 샌드위치와 주스 가게였죠. 16살 때 이런 일을 많이 했었죠. 레스토랑에서도 일하고 다양한 일을 했었어요. 이런 일들이 중요하다고 생각해요. 이때 부지런함이나 모든 일에 최선을 다해야 한다는 것을 배웠어요. 대학교 졸업 이후에는 투자은행인 골드만삭스에서 일을 시작했어요. 제가 기대했던 것보다 그렇게 즐기진 않아서 컨설팅 쪽으로 옮겼어요. 보스턴 컨설팅 그룹에서 일하게 되었죠. 그 후 친구와 스타트 업을 하려고 했지만 잘 되진 않았죠. 하지만 그때부터 스타트업의 기 술적인 부분에 관심을 가지기 시작했죠. 그래서 구글 본사의 전략팀에서 몇 년 일했고, 그 이후에 미미박스에 조인하게 되었어요.Q. 이제 미미박스에서 스피드만큼이나 완벽함을 추구하려고 하고 있는데요. 아놀드는 어떻게 일을 완벽하게 끝내시나요?! A.  제가 '완벽'하게 일을 끝낸 적이 있다고 생각하진 않아요. 완벽이란 일종의 환상이라고 생각해요. 완벽에 대해선 '과정'이 중요하다고 생각해요. 제가 아웃풋을 낼 수 있는 한두 분야에 집중하죠. 그 한두 분야에 정말 정말 집중하고 강하게 끌고가요 그리고 시간이 지날수록 그 일을 발전시켜가요. 이런 식으로 저는 과정에 집중하고 과정에 완벽이 있다고 생각해요. Q. 미미박스에 있으면서 이루고 싶은 버킷리스트가 있나요?A.  제겐 중요한 세 개의 버킷리스트가 있어요. 하나는 멋진 사람들과 일할 수 있는 기회죠. 제가 배울 수 있고 영감을 받을 수 있는 사람들을 찾고 싶어요. 두 번째는 그들을 위한 환경을 만드는 것이죠. 자신의 일로 인해 신나고 함께 일하는 사람들로 인해 항상 기대되는 환경을 글로벌하게 만들고 싶어요. 마지막으로는 서울에서 시작한 스타트 업을 보고 그 스타트업이 미국에서 어떻게 성장하고 커가는지 이해하고 기대하는 것이죠. 또한 미국 오피스에서는 이런 것들이 세계적으로 퍼질 수 있도록 노력하고 있습니다. 세 번째는 훌륭한 사람들과 일하고 그들을 발전시켜가며 제가 가지게 된 목표는 많은 미미박서들이 서로 배워서 자신이 세운 회사를 시작하는 것입니다. 그들이 원하는 세상을 그들이 만든 회사로 만들어가는 것이죠. 이런 것들이 제가 돌아봤을 때 정말 자랑스러운 일이 될 것 같아요. 미미박스 동창회 같은 것이죠. 미미박스에 멈추지 않고 나가서 세상에 커다란 영향을 끼쳐야 하죠. 그렇게 미래의 창업자들에게 영감을 주고 그들이 원하는 만큼 배우고 성장할 수 있도록 만들고 싶어요. Q. 미미박스에 대해 어떤 비전을 가지고 있으신가요? A.  제가 가지고 있는 비전은 미미박스가 세계 최고의 테크 기반의 결합된 뷰티 회사(technology driven connected beauty company)가 되는 것입니다. 커넥티드 뷰티(connected beauty)란 세상에 정말 많은 뷰티 브랜드가 있잖아요. 그들은 단지 마케팅을 바꾸고 타겟 고객을 바꾸는 것 같아요. 같은 브랜드로 한 그룹에 팔고 같은 브랜드로 마케팅만 다르게 해서 다양한 그룹에 파는 것이죠. 제 생각엔 미미박스는 정말 특별해질 수 있어요. 브랜드와 제품을 한 타겟 그룹의 감정선까지 연결해서 전문적이고 특별하게 만들 수 있죠. 데이터, 기술, 브랜딩, 마케팅 미 모두를 함께 이용해서 말이죠. 이런 것들이 미래가 될 거예요. 패션 사업과도 비슷해요. 패스트패션(fast-fashion) 산업은 빠르게 변하는 컨셉이 패션 산업을 완전히 바꾸고 있죠. 저는 정말 커넥티드 뷰티가 기술, 브랜딩, 데이터, 마케팅 등을 모아 고객을 위해 의미 있는 커넥션을 들 거라고 생각해요. 이런 것들이 산업을 바꿔나갈 거예요. 패스트패션이 산업을 바꾸듯이 커넥티드 뷰티가 산업을 바꿔나갈 거예요. 이런 것들이 제가 기대하는 것들이에요. 단기적으로는 훌륭한 사람들을 모으고 즐겁게 일하며 이일을 발전시키는 것이 제 비전이에요.
조회수 2012

다양한 형태를 지원하는 리스트 UI, 잘 그리고 계신가요?

대략 1년 반 전, 5.0 롤리팝과 함께 나타난 RecyclerView. ListView 를 이용할 때 아주 기초적이고 정석적인 개념으로 사용되던 ViewHolder pattern 을 반 강제화? 하면서 동시에 성능까지 개선한 ListView 의 개량버전.앱 시장이 활성화되면서 한 가지 타입의 뷰만 반복적으로 보여주는 단순한 구성보다는 다양한 타입의 뷰를 보여주는 앱들이 많아지고 보편화 된 시점에 이것을 구현하기 위한 Adapter.getView 메소드는 혼돈.chaos 가 되었지요. 가독성을 높일만한 나름대로의 시도를 해보고 있을 때, RecyclerView 가 갑툭튀 했고 이걸 이용하면 원하는 만큼의 많은 타입의 뷰를 “가독성 좋게 만들어 볼 수 있겠다” 라는 생각이 들었습니다.그래서 RecyclerView.Adapter 를 상속 받아 다양한 타입의 뷰를 바인딩 할 수 있게 도와주는 헬퍼 클래스, MultiItemAdapter 라는 것을 만들어 보게 됐습니다. 구 회사 프로덕트에 적용해보기도 하고, 개인 프로젝트에 넣어보기도 하고, 토스랩에서 서비스하고 있는 “잔디”에 녹여내보기도 했는데 나쁘지 않은 느낌이들어 그 과정을 공유하고 많은 분들께 피드백도 받고 싶습니다. 또, 어떻게 더 잘 활용하고 계신지 여쭙고 싶습니다.RecyclerView.Adapter 의 이해를 위해 단순단순하게 만들어보자public class BasicAdapter extends RecyclerView.Adapter { private List mItems = new ArrayList<>(); @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(parent.getContext()) .inflate(android.R.layout.simple_list_item_1, parent, false); return new MyViewHolder(itemView); } @Override public void onBindViewHolder(MyViewHolder holder, int position) { holder.mTextView.setText(mItems.get(position)); } class MyViewHolder extends RecyclerView.ViewHolder { private TextView mTextView; public MyViewHolder(View itemView) { super(itemView); mTextView = (TextView) itemView.findViewById(android.R.id.text1); } } ... 이런 식으로 구현하면 되는군, 하지만 내가 최종적으로 원하는 건 다양한 ViewHolder 를 다뤄야 되는 건데 ViewHolder 가 많아지는 경우 inner class 는 쓰면 안되겠다! ViewHolder 들은 따로 패키지 만들어서 관리하자. 음 근데 ViewHolder 를 구성하고 난 다음 어떻게 그려지는 지에 대해 궁금하면 다시 어댑터를 찾아가야 되고, 반대로 어댑터에서 ViewHolder 내 구성요소가 어떻게 생겼는지 궁금하면 다시 ViewHolder 찾아가서 뒤져봐야되는 군. 이건 비효율 적인 것 같다. ViewHolder에 뷰를 그리는 메소드를 하나 만들자. 아 기왕이면 추상화된 클래스를 만들어 돌려돌려 쓰자. 하나 더 Generic 을 사용하자.public abstract class BaseViewHolder extends RecyclerView.ViewHolder { public BaseViewHolder(View itemView) { super(itemView); } public abstract void onBindView(ITEM item); } 뷰를 그리는데 쓰이는 객체는 Generic 을 이용하면 ViewHolder 안에서 그리는 작업 또한 해결이 가능하겠군! 이걸 이용해서 다시 만들어보자.public class MyViewHolder extends BaseViewHolder { private TextView mTextView; public MyViewHolder(View itemView) { super(itemView); mTextView = (TextView) itemView.findViewById(android.R.id.text1); } @Override public void onBindView(String item) { mTextView.setText(item); } } ... public class BaseAdapter extends RecyclerView.Adapter { private List mItems = new ArrayList<>(); @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(parent.getContext()) .inflate(android.R.layout.simple_list_item_1, parent, false); return new MyViewHolder(itemView); } @Override public void onBindViewHolder(MyViewHolder holder, int position) { holder.onBindView(mItems.get(position)); } public void setItems(List items) { mItems.clear(); mItems.addAll(items); } @Override public int getItemCount() { return mItems.size(); } } 음 원하는 모양새다. 근데 이제 Adapter 에선 ViewHolder 에 들어갈 layout 이 어떤 건지 관심꺼도 되겠네. 게다가 ViewHolder 에서 layout 궁금하면 다시 또 찾아와야 되는게 문제다. 좀 더 명시적인 방법으로 Factory method 로 생성자를 제한해보자. RecyclerView.ViewHolder 는 View 를 가지는 생성자가 강제되니 이렇게 바꾸자.public static MyViewHolder newInstance(ViewGroup parent) { View itemView = LayoutInflater.from(parent.getContext()) .inflate(android.R.layout.simple_list_item_1, parent, false); return new MyViewHolder(itemView); } private MyViewHolder(View itemView) { super(itemView); mTextView = (TextView) itemView.findViewById(android.R.id.text1); } 이렇게 하면 어떤 layout 을 다루고 있는지도 금방 알 수 있겠다. 이 정도만 되도 구색을 다 갖춘듯하니 이 느낌으로 다양한 타입의 뷰들을 다뤄보자.public class BasicMultiTypeAdapter extends RecyclerView.Adapter { public static final int VIEW_TYPE_A = 0; public static final int VIEW_TYPE_B = 1; private List mItems = new ArrayList<>(); @Override public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == VIEW_TYPE_A) { return AViewHolder.newInstance(parent); } else { return BViewHolder.newInstance(parent); } } @Override public void onBindViewHolder(BaseViewHolder holder, int position) { holder.onBindView(mItems.get(position)); } public void setItems(List items) { mItems.clear(); mItems.addAll(items); } @Override public int getItemCount() { return mItems.size(); } @Override public int getItemViewType(int position) { if (position % 2 == 0) { return VIEW_TYPE_A; } else { return VIEW_TYPE_B; } } } 음 깔끔하긴 하다. 근데 getItemViewType 이 스크롤 할 때마다 불릴 텐데, 분기도 많고 연산이 생겼을 때 스크롤 속도에 괜한 영향을 줄 듯? view type 을 차라리 미리 가지고 있게 만들자. 또! 가만보니 한 타입의 객체를 이용해서 다른 스타일로 뷰를 보여줄 뿐이었네. 이것도 여러가지 객체를 담을 수 있게 만들어야지.뷰를 그릴 대상이 될 객체랑 타입을 가지는 Wrapper class 를 만들어서 해결하자. 이러면 Adapter.onBindViewHolder 랑 Adapter.getItemViewType 도 해결이 되겠군.public abstract class MultiItemAdapter extends RecyclerView.Adapter { private List mRows = new ArrayList<>(); @SuppressWarnings("unchecked") @Override public void onBindViewHolder(BaseViewHolder holder, int position) { holder.onBindView(getItem(position)); } @SuppressWarnings("unchecked") public ITEM getItem(int position) { return (ITEM) mRows.get(position).getItem(); } public void setRows(List mRows) { mRows.clear(); mRows.addAll(mRows); } @Override public int getItemCount() { return mRows.size(); } @Override public int getItemViewType(int position) { return mRows.get(position).getItemViewType(); } public static class Row { private ITEM item; private int itemViewType; private Row(ITEM item, int itemViewType) { this.item = item; this.itemViewType = itemViewType; } public static Row create(T item, int itemViewType) { return new Row<>(item, itemViewType); } public ITEM getItem() { return item; } public int getItemViewType() { return itemViewType; } } } MultiItemAdapter 완성.네, 저는 이렇게 만들어서 1년 반 정도 필요한 부분(복잡해 질만한 부분)에 이 클래스를 상속받아 구현했습니다. 사용방법을 예로들어 데이터베이스나 서버로부터 긁어온 아이템들을 타입에 따라 A, B로 나눠서 보워줘야 한다면,// MutiItemAdapter 구현 public class AdvancedItemAdapter extends MultiItemAdapter { public static final int VIEW_TYPE_A = 0; public static final int VIEW_TYPE_B = 1; @Override public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == VIEW_TYPE_A) { return AViewHolder.newInstance(parent); } else { return BViewHolder.newInstance(parent); } } } // Activity 나 Fragment 등 view 요소에서 ListAdapter item setting. public void setItems(List items) { List rows = new ArrayList<>(); for (int i = 0; i < items xss=removed>이렇게 해주면 됩니다. 그런데 위 사용방법을 보면 추가적인 새로운 타입(Row)의 List 와 반복문을 돌려야 된다는 것이 단점으로 보이는데요. 그럼 이 클래스를 사용하지 않고 직접 구현한 결과를 좀 볼까요?public class NormalItemAdapter extends RecyclerView.Adapter { public static final int VIEW_TYPE_A = 0; public static final int VIEW_TYPE_B = 1; private List mItems = new ArrayList<>(); @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == VIEW_TYPE_A) { View itemView = LayoutInflater.from(parent.getContext()) .inflate(android.R.layout.simple_list_item_1, parent, false); return new AViewHolder(itemView); } else { View itemView = LayoutInflater.from(parent.getContext()) .inflate(android.R.layout.simple_list_item_1, parent, false); return new BViewHolder(itemView); } } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (holder instanceof AViewHolder) { Item item = getItem(position); ((AViewHolder) holder).getTextView().setText(item.getName()); } else { ((BViewHolder) holder).getTextView().setText("I am B."); } } private Item getItem(int position) { return mItems.get(position); } public void setItems(List items) { mItems.clear(); mItems.addAll(items); } @Override public int getItemViewType(int position) { if (getItem(position).getType().equals(Item.ITEM_TYPE_A)) { return VIEW_TYPE_A; } else { return VIEW_TYPE_B; } } @Override public int getItemCount() { return mItems.size(); } } 뭐, 나쁘진 않습니다. 이 정도 수준으로 개발이 끝나도 되고 추가적인 확장이 필요하지 않아보인다면 굳이 MultiItemAdapter 를 쓸 필요가 없습니다.중요성을 가지는 리스트 위주의 화면에서 위와 같이 개발된다면 당장 보이는 제 불만은 onCreateViewHolder, onBindViewHolder 계속해서 분기가 들어가게 되고 getItemViewType 에서는 계속 해서 List 데이터에 접근해야 한다는 것입니다. 접근 자체가 큰 문제, 큰 영향을 끼치지 않을 정도 규모의 자료구조라면 논외로 치더라도, 뷰 타입이 조금만 늘어나도 onCreateViewHolder, onBindViewHolder 의 덩치는 엄청 커질 겁니다.예를들면 맨 마지막 아이템 타입이 B 이고 현재 추가 될 아이템 타입이 A인 경우에는 다른 형태의 디바이더를 넣어야 한다던지 하는 추가적인 확장이 이루어져야 한다면 골치가 꽤 아플겁니다. 특히 저는 위 예와 비슷하게 뷰 타입에 따라 각기 다른 아래 위 마진값을 요구받을 때, ViewHolder 마다 이전 데이터를 참고하게 만들고 동적으로 Visibility 처리를 하거나 MarginLayoutParams 를 고치는 것이 비효율적으로 느껴져서 height를 주입받는 DividerViewHolder 를 하나 만들어 사용하곤 했습니다. 이렇게 하니 각각의 ViewHolder 들이 데이터들에 의존적이지 않게 코딩이 가능했었습니다. 한 가지 더 예를들어 리스트 중간 중간 광고가 보여지게 되고 이 광고 클래스는 완전히 다른 객체로부터 보여줘야 한다 라고 했을 때 MultiItemAdapter 를 이용하면 쉽게 해결이 가능합니다.정작 근 1년간 “잔디”를 만들면서는 자주 쓰진 않았는데, 작년부터 각광받기 시작한 MVP 패턴을 사용할 때 View 에서의 로직을 최소화 하려고 한다면 써먹을 수 있는 모델로 적합하지 않나 생각이 들면서 다시 사용하기 시작했습니다. Presenter 에서 Row 를 만들어 던져주면 View 는 그것을 그대로 사용하게 만들 수 있다는 생각이 들었거든요.(아직까지는 비교적 크지 않은 부분에서만 사용하게 되서 View(MainThread)에서 Row 를 만들게 코딩해 놓은 컴퍼넌트가 더 많네요 흑흑) 더 복잡한 구조를 갖는 컴퍼넌트를 만들어야 할 때는 비동기 스레드에서 Row 까지 만들어 내보내는 것도 해볼까 하는 생각도 듭니다.제 눈에만 괜찮은 구조인지, 생각지도 못한 치명적인 단점이 있진 않은지, 구조나 설계 측면에서 안 좋은 점은 있지 않은지, 논리없이 Generic 으로 “퉁” 치고 있는 코드는 아닌지, 여러가지가 많이 궁금합니다 ^^ MultiItemAdapter 를 쓴 것과 안 쓴것의 정말 심플한 비교 소스를 열어놓았습니다 MultiItemAdapter 또, 여러분들은 어떻게 구현하고 계신지요? 여러분의 관심이 필요합니다 ! :)#토스랩 #잔디 #JANDI #개발 #개발자 #인사이트 #경험공유
조회수 3999

리디북스 서비스 장애 복구 후기

지난 8월 26일에는 약 21분간 리디북스 서비스 전체가 중단되는 장애가 있었습니다.사실 서버 스택 일부에만 영향을 주는 장애는 눈에 잘 띄지 않지만 꽤 흔하게 발생하는 일입니다. 기기 1대당 외부적인 요인으로 인한 장애가 평균 2년에 1번 발생한다고 가정하면, 서버가 100대 있을 때는 대략 1주일에 1번꼴로 장애가 발생하는 셈입니다.이런 형태의 장애는 서버 스택의 한 곳에서만 발생하므로, 이중화 혹은 클러스터링을 통해서 극복하곤 합니다. 또한 원인이 명확하므로 해당 기술에 대한 이해도가 높다면 비교적 빠른 시간 내에 복구가 가능합니다.그러나 이번에 리디북스가 경험한 장애는 달랐습니다. 현재 리디북스는 2개의 데이터센터와 클라우드에 인프라가 분산되어 있는데, 이 중에서 1차 데이터센터의 전원 공급에 문제가 생겨 특정 서버 랙에 있는 서버 17대가 동시에 내려간 것입니다. 즉, 소프트웨어나 머신의 물리적인 장애가 아닌, 데이터센터의 장애였습니다. AWS로 비유를 하자면 가용 영역(Availability Zone)의 장애라고 할 수 있겠습니다.원인에 대해이번 장애의 근본적인 원인은 데이터센터가 전원을 정상적으로 공급해주지 못한 것입니다. 물론 데이터센터 혹은 클라우드 서비스(IaaS)는 고객사에게 전원과 네트워크를 안정적으로 제공해주어야 하는 의무가 있습니다.하지만 이들 역시 천재지변이나 사람의 실수에 대한 대비가 100% 완벽할 수는 없습니다. 따라서 이러한 점을 사전에 고려하고 인프라를 설계하지 못한 것이 2차적인 원인입니다.이번 계기를 통해 데이터센터 이중화를 계획하게 되었고, 사용 중인 클라우드 역시 지역(Region) 전체에 장애가 생길 경우에 대한 대비가 되어있지 않아, 이번 계기로 복제 계획(Geo-Replication)을 세우게 되었습니다.구체적인 상황당시 전원이 차단되어 강제 종료된 서버들은 아래와 같습니다.데이터베이스 프록시 x 2메인 리버스 프록시 x 1읽기 분산용 MySQL 슬레이브 x 1서점용 웹 서버 x 3추천 알고리즘 API 서버 x 1알림센터 API 서버 x 2메인 스토리지 서버 x 2출판 플랫폼용 데이터베이스 x 2테스트 및 배치 작업용 서버 x 3그림으로 표현해 보자면, 대략 아래와 같은 상황에서… 아래와 같은 상황이 된 셈입니다.서버 스택의 여러곳에 순간적으로 장애가 발생한 상황공인 IP가 할당된 메인 프록시 서버 중 1대가 내려갔지만, 실제로는 아래와 같이 가상 IP로 구성을 한 상태였기 때문에 대기 중인(stand-by) 프록시가 동작하여 곧 서점에 장애 공지를 띄울 수 있었습니다.[이미지 출처: DigitalOcean™]공지 이후의 움직임우리는 데이터센터의 복구 시점을 명확히 알 수 없어서 신규 구축(provisioning)을 시작함과 동시에, 서버들의 물리적인 위치 이동을 고려하고 있었습니다. 그러나 다행히 10분이 지난 시점에서 전원 문제는 해결되었고, 서버들은 순차적으로 부팅이 완료되었습니다.일부 서버들은 부팅 과정에서 예상치 못한 지연이 발생하기도 하였지만, 모든 서버의 부팅이 완료된 이후에도 서비스는 완전히 정상으로 돌아오지 않았습니다. 당시 우리가 겪었던 문제와 해결책은 아래와 같습니다.A. 읽기 분산용 MariaDB 슬레이브의 복제 지연(replication lag) 문제슬레이브 서버의 부팅이 완료되자 데이터베이스 프록시(HAProxy)는 해당 서버를 정상으로 간주하여 라우팅 대상에 포함하게 되었고, 애플리케이션 서버들은 정상적으로 커넥션을 맺기 시작하였습니다. 하지만 해당 슬레이브는 수십 분간 마스터를 따라잡지 못한 상태였기 때문에 최신 데이터가 보여지지 않는 문제(stale data)가 있었습니다. 우리는 즉시 해당 슬레이브를 제거하였고 지연이 사라진 이후에 다시 서비스에 투입하였습니다.B. 읽기 분산용 슬레이브의 웜업(warm-up) 문제복제 지연은 사라졌지만 서버의 CPU 사용량이 크게 높은 상태가 한동안 유지되었고, 응답속도는 정상적인 슬레이브에 비해서 많이 느렸습니다. 왜냐하면 캐시가 비워진 상태에서 바로 서비스에 투입되어, 캐시 미스가 휘몰아치는 현상(cache stampede)이 발생하였기 때문입니다. 따라서 간단한 쿼리도 평소보다 오래 걸렸고, 그대로 둔다면 커넥션풀이 꽉 차는 현상이 발생할 것으로 예상되었습니다.곧 우리는 HAProxy로 해당 서버의 가중치를 10%로 낮추어 인입되는 쿼리의 양을 조절하였으며 응답속도는 정상 수치로 돌아오게 되었습니다. 이후 스크립트를 작성하여 수동으로 캐시를 채워나감과 동시에 점차 가중치를 높여 처리량을 정상화하였습니다.프로덕션에서 사용하는 서버는 innodb_buffer_pool 이 100G 이상으로 매우 크게 설정되어 있으며, 재시작 시 캐시가 날아가는 현상을 해결하기 위해 innodb_blocking_buffer_pool_restore 옵션을 적용하고 있습니다. 하지만 지금처럼 메모리를 덤프하지 못하고 비정상 종료가 된 상황에서는 해당되지 않았습니다.C. 인메모리 데이터의 보존 문제알림센터는 다양한 프로모션과 개인화된 정보를 전달해주는 공간입니다. 알림센터의 특징은 데이터의 영구 보존(persistency)이 필요하지 않고, 매일 수백만 건의 개인화된 메시지가 기록된다는 것입니다. 이러한 특징은 인-메모리 데이터베이스에 적합하므로 우리는 Redis를 마스터/슬레이브로 구성하여 저장소로 사용하고 있었습니다.어떠한 이유로든 Redis를 재시작해야 할 경우가 생기면, 메모리 상의 데이터가 날아가는 것을 방지하기 위해 주기적으로 스냅샷을 남기고 있습니다만, 이번에는 로그가 마지막까지 기록되지 못한 상태에서 메모리의 데이터가 날아가 버렸습니다.다행히 알림 발송과 관련된 메타정보는 모두 MariaDB에 기록하고 있으므로, 우리는 이를 기반으로 소실된 시점부터의 알림을 순차적으로 재발송할 수 있었습니다. 물론 모든 알림이 신규 상태로 간주되어 아이콘이 잘못 노출되는 문제가 있었지만, 고객님들은 너그럽게 이해해 주신 것 같습니다. 😅그래서 앞으로는?리디북스 DevOps 멤버들은 이번 데이터센터 장애를 통해 현재 인프라의 한계점을 실감하였고, 앞으로의 개선 방향에 대해 고민하게 되었습니다.몇 가지를 정리하면 다음과 같습니다.랙 단위로 장애가 발생할 수 있음을 인지하고 대비하자.같은 기능을 하는 서버를 하나의 랙이나 같은 가용 영역에 두지 말자.2차 데이터센터는 더 이상 옵션이 아닌 필수다.낙뢰나 지진으로 인해 데이터센터에 문제가 생길 수도 있다.긴급하게 프로비저닝이 필요한 상황에 대비하자.문서화가 되어 있더라도 경험이 없다면 동일한 구성에 많은 시간이 소요된다.모든 구성요소들에 대한 Ansible 스크립트를 작성하여두자.캐시 웜업 스크립트도 작성하여 두자.백엔드 구성요소들 간의 불필요한 의존 관계를 끊자.단 한 줄의 코드라도 참조하고 있다면 이는 독립적인 것이 아니다.언제나 서비스 지향적인 설계를 추구하자.Uptime을 관리하자.최대 180일을 기점으로 무조건 리부팅을 하자.재시작 과정에서 다양한 문제와 개선점이 발견될 것이다.커널 패치, 보안 패치를 할 수 있는 것은 덤이다.아래와 같은 긍정적인 면도 발견하였습니다.장애 상황이 실시간으로 Slack 채널을 통해 전파되었음진행 상황에 대해 모두가 동일한 수준으로 이해할 수 있었다.모니터링 연동(integration) 기능 때문에라도, Slack은 유료로 구매할만한 값어치가 충분하다.같은 기능을 하는 서버들이 다른 랙에 많이 분산되어 있었다.인프라가 확장될 때마다 빈 공간에 필요한 서버를 추가했을 뿐이지만, 자연스럽게 물리적인 위치가 분산되는 효과가 있었다.이 외에도 특정 클러스터를 구성하는 노드들을 분산하여 배치시키자.서버별로 오너쉽이 부여되어 있어서 빠르게 복구가 된 점여러 명의 백엔드 개발자들이 병렬적으로 복구를 진행할 수 있었다.마지막으로넷플릭스의 엔지니어들은 무질서한 원숭이(Chaos Monkey)라는 프로그램을 만들어서 운영한다고 합니다. 이 원숭이는 서비스 인스턴스들을 무작위로 중단시키는 역할을 합니다. 다소 황당하게 들리지만, 넷플릭스에는 일부 서비스에 장애가 발생하더라도 나머지 부분은 문제없이 운영되어야 한다는 원칙이 있으므로, 이를 수시로 시뮬레이션하는 과정을 통해 복구 능력을 높여둔다는 것입니다.실제로 이렇게 급진적인 아이디어를 실천할 수 있는 회사는 매우 드물 것입니다. 하지만, 우리는 이번 계기를 통해 무질서한 원숭이의 필요성을 절감하였고, 이로 인해 서버를 주기적으로 리셋하는 정책을 만들게 되었으며 모든 단일 장애점(SPoF)에 대한 대비를 시작하게 되었습니다.장애를 단순히 피해라고만 생각한다면, 서로를 비난하고 책임을 전가하는 상황이 펼쳐질 것입니다. 하지만 고객의 불편함과 맞바꾼 매우 비싼 경험이라고 생각한다면, 보다 튼튼하고 회복탄력적인 시스템을 갖추기 위해 노력하게 될 것입니다. 그러다 보면 언젠가는 데이터센터 전체에 문제가 생겨도 버틸 수 있는 모습으로 진화할 것이라고 생각합니다.#리디북스 #장애복구 #역경돌파 #개발 #개발후기 #개발자 #서버개발 #서버
조회수 818

KBS 분야별 업무소개 - 기자

역사의 현장, 그 현장으로 당신을 초대합니다! ′우리의 1년은 세계의 10년′이란 말이 있습니다.격동의 근대사를 숨가쁘게 달려온 우리는 지금 이 순간에도 하루 하루 사회 전 분야에서 일어나는 역동적인 변화를 온 몸으로 느끼며 살아가고 있습니다. 그 가슴 벅찬 변화의 숨결을 현장에서 생생하게 느껴보시지 않겠습니까?.백두에서 한라까지, 그리고 오대양 육대주 구석구석까지 역사적인 사건의 현장에는 어김없이 KBS의 기자들이 있습니다. 그 현장의 주인공으로 여러분을 초대합니다. KBS 뉴스는 언제나 어디서나 국민들이 가장 많이 시청하고 있는 명실상부한 한국 최고의 뉴스입니다. 최고의 시청률, 최고의 영향력으로 타 방송사는 물론 타 언론사를 압도하고 있습니다.4천3백만 국민들은 KBS의 뉴스광장과 함께 하루를 열고, 9시 뉴스에서 가장 알차고 신뢰할 수 있는 품격 높은 정보를 얻으며, 뉴스라인으로 하루를 마감하고 있습니다. 24시간 깨어있는 KBS 뉴스야말로 우리 국민들이 호흡하며 살아가는 산소와 같은 존재로 자리매김 했습니다. 가장 영향력 있는 KBS 뉴스 뒤에는 지금 이 시간에도 전국 취재 현장을 누비고 있는 600여명의 기자들이 있습니다. 또 언론사 가운데 가장 많은 20여명의 특파원이 세계의 소식을 시시각각 전해오고 있습니다.한국사회를 이끌어간다는 자부심으로 24시간 뛰고 있는 KBS의 기자들은 땀과 정열 그리고 사명감으로 역사의 현장을 취재하고 제작하고 또 방송하고 있습니다. 내가 쓴 기사, 내가 제작한 리포트가 가져다 주는 부듯한 성취감, 그리고 타 매체에서는 느낄 수 없는 선후배 동료 간의 끈끈한 유대, 신명나는 판에서만 느낄 수 있는 땀방울의 환희가 보도본부에는 있습니다.디지털 시대의 번뜩이는 감성과 지성, 그리고 영상감각으로 무장한 여러분들을 KBS 뉴스의 주인공으로 초대합니다. 이미 미디어의 주도권은 활자매체에서 영상매체로 넘어온 지 오랩니다. 그리고 그 격차는 더욱 벌어질 것입니다. 니이체는 세상에 두 부류의 사람이 있다고 했습니다. ′역사를 만들어 가는 사람과 평가하는 사람′ KBS 기자는 ′역사를 만들어 가는 동시에 평가하는 사람′ 들입니다. 지금 당신과 함께 우리의 역사를 함께 이끌어가고 또 평가해가고 싶습니다.일하는 즐거움과 감동을 KBS 뉴스에서 느껴보시기 바랍니다. KBS 보도본부로 오십시오.여기가 바로 여러분이 춤 출 이상의 섬 ′로도스′입니다.#한국방송공사 #KBS #KBS공채 #직무정보 #직무소개
조회수 1575

VCNC가 Hadoop대신 Spark를 선택한 이유

요즘은 데이터 분석이 스타트업, 대기업 가릴 것 없이 유행입니다. VCNC도 비트윈 출시 때부터 지금까지 데이터 분석을 해오고 있고, 데이터 기반의 의사결정을 내리고 있습니다.데이터 분석을 하는데 처음부터 복잡한 기술이 필요한 것은 아닙니다. Flurry, Google Analytics 등의 훌륭한 무료 툴들이 있습니다. 하지만 이러한 범용 툴에서 제공하는 것 이상의 특수하고 자세한 분석을 하고 싶을 때 직접 많은 데이터를 다루는 빅데이터 분석을 하게 됩니다. VCNC에서도 비트윈의 복잡한 회원 가입 프로세스나, 채팅, 모멘츠 등 다양한 기능에 대해 심층적인 분석을 위해 직접 데이터를 분석하고 있습니다.빅데이터 분석 기술큰 데이터를 다룰 때 가장 많이 쓰는 기술은 Hadoop MapReduce와 연관 기술인 Hive입니다. 구글의 논문으로부터 영감을 받아 이를 구현한 오픈소스 프로젝트인 Hadoop은 클러스터 컴퓨팅 프레임웍으로 비싼 슈퍼컴퓨터를 사지 않아도, 컴퓨터를 여러 대 연결하면 대수에 따라서 데이터 처리 성능이 스케일되는 기술입니다. 세상에 나온지 10년이 넘었지만 아직도 잘 쓰이고 있으며 데이터가 많아지고 컴퓨터가 저렴해지면서 점점 더 많이 쓰이고 있습니다. VCNC도 작년까지는 데이터 분석을 하는데 MapReduce를 많이 사용했습니다.주스를 만드는 과정에 빗대어 MapReduce를 설명한 그림. 함수형 프로그래밍의 기본 개념인 Map, Reduce라는 프레임을 활용하여 여러 가지 문제를 병렬적으로 처리할 수 있다. MapReduce slideshare 참조MapReduce는 슈퍼컴퓨터 없이도 저렴한 서버를 여러 대 연결하여 빅데이터 분석을 가능하게 해 준 혁신적인 기술이지만 10년이 지나니 여러 가지 단점들이 보이게 되었습니다. 우선 과도하게 복잡한 코드를 짜야합니다. 아래는 간단한 Word Count 예제를 MapReduce로 구현한 것인데 매우 어렵고 복잡합니다.MapReduce로 단어 갯수를 카운트하는 간단한 예제 (Java). 많은 코드를 작성해야 한다.이의 대안으로 SQL을 MapReduce로 변환해주는 Hive 프로젝트가 있어 많은 사람이 잘 사용하고 있지만, 쿼리를 최적화하기가 어렵고 속도가 더 느려지는 경우가 많다는 어려움이 있습니다.MapReduce의 대안으로 최근 아주 뜨거운 기술이 있는데 바로 Apache Spark입니다. Spark는 Hadoop MapReduce와 비슷한 목적을 해결하기 위한 클러스터 컴퓨팅 프레임웍으로, 메모리를 활용한 아주 빠른 데이터 처리가 특징입니다. 또한, 함수형 프로그래밍이 가능한 언어인 Scala를 사용하여 코드가 매우 간단하며, interactive shell을 사용할 수 있습니다.Spark으로 단어 개수를 카운트하는 간단한 예제 (Scala). MapReduce에 비해 훨씬 간단하다.Spark과 MapReduce의 성능 비교. I/O intensive 한 작업은 성능이 극적으로 향상되며, CPU intensive 한 작업의 경우에도 효율이 더 높다. (자료: RDD 논문)Apache Spark는 미국이나 중국에서는 현재 Hadoop을 대체할만한 기술로 급부상하고 있으며, 국내에도 최신 기술에 발 빠른 사람들은 이미 사용하고 있거나, 관심을 갖고 있습니다. 성능이 좋고 사용하기 쉬울 뿐 아니라, 범용으로 사용할 수 있는 프레임웍이기에 앞으로 더 여러 분야에서 많이 사용하게 될 것입니다. 아직 Spark를 접해보지 못하신 분들은 한번 시간을 내어 살펴보시길 추천합니다.기존의 데이터 분석 시스템 아키텍처기존의 데이터 분석 시스템 아키텍처기존의 시스템은 비용을 줄이기 위해 머신들을 사무실 구석에 놓고 직접 관리했으며, AWS S3 Tokyo Region에 있는 로그를 다운받아 따로 저장한 뒤, MapReduce로 계산을 하고 dashboard를 위한 사이트를 따로 제작하여 운영하고 있었습니다.이러한 시스템은 빅데이터 분석을 할 수 있다는 것 외에는 불편한 점이 많았습니다. 자주 고장 나는 하드웨어를 수리하느라 바빴고, 충분히 많은 머신을 확보할 여유가 없었기 때문에 분석 시간도 아주 오래 걸렸습니다. 그리고 분석부터 시각화까지 과정이 복잡하였기 때문에 간단한 것이라도 구현하려면 시간과 노력이 많이 들었습니다.Spark과 Zeppelin을 만나다이때 저희의 관심을 끈 것이 바로 Apache Spark입니다. MapReduce에 비해 성능과 인터페이스가 월등히 좋은 데다가 0.x 버전과는 달리 1.0 버전에서 많은 문제가 해결되면서 안정적으로 운영할 수 있어 비트윈 데이터 분석팀에서는 Spark 도입을 결정했습니다.Apache Zeppelin은 국내에서 주도하고 있는 오픈소스 프로젝트로써, Spark를 훨씬 더 편하고 강력하게 사용할 수 있게 해주는 도구입니다. 주요한 역할은 노트북 툴, 즉 shell에서 사용할 코드를 기록하고 재실행할 수 있도록 관리해주는 역할과 코드나 쿼리의 실행 결과를 차트나 표 등으로 시각화해서 보여주는 역할입니다. VCNC에서는 Zeppelin의 초기 버전부터 관심을 가지고 살펴보다가, Apache Spark를 엔진으로 사용하도록 바뀐 이후에 활용성이 대폭 좋아졌다고 판단하여 데이터 분석에 Zeppelin을 도입하여 사용하고 있고, 개발에도 참여하고 있습니다.또한, 위에서 언급한 하드웨어 관리에 드는 노력을 줄이기 위해서 전적으로 클라우드를 사용하기로 함에 따라서1 아래와 같은 새로운 구조를 가지게 되었습니다.새로운 데이터 분석 시스템 아키텍처새로운 데이터 분석 시스템 아키텍처새로운 데이터 분석 시스템은 아키텍처라고 하기에 다소 부끄러울 정도로 간단합니다. 애초에 전체 시스템 구성을 간단하게 만드는 것에 중점을 두었기 때문입니다. 대략적인 구성과 활용법은 아래와 같습니다.모든 서버는 AWS 클라우드를 이용수 대의 Zeppelin 서버, 수 대의 Spark 서버운영Spark 서버는 메모리가 중요하므로 EC2 R3 instance 사용로그는 별도로 저장하지 않고 서비스 서버에서 S3로 업로드하는 로그를 곧바로 가져와서 분석함중간 결과 저장도 별도의 데이터베이스를 두지 않고 S3에 파일로 저장Zeppelin의 scheduler 기능을 이용하여 daily batch 작업 수행별도의 dashboard용 Zeppelin을 통해 중간 결과를 시각화하며 팀에 결과 공유이렇게 간단한 구조이긴 하지만 Apache Spark와 Apache Zeppelin을 활용한 이 시스템의 능력은 기존 시스템보다 더 강력하고, 더 다양한 일을 더 빠르게 해낼 수 있습니다.기존현재일일 배치 분석코드 작성 및 관리가 어려움Zeppelin의 Schedule 기능을 통해 수행 Interactive shell로 쉽게 데이터를 탐험 오류가 생긴 경우에 shell을 통해 손쉽게 원인 발견 및 수정 가능Ad-hoc(즉석) 분석복잡하고 많은 코드를 짜야 함분석 작업에 수 일 소요Interactive shell 환경에서 즉시 분석 수행 가능Dashboard별도의 사이트를 제작하여 운영 관리가 어렵고 오류 대응 힘듦Zeppelin report mode 사용해서 제작 코드가 바로 시각화되므로 제작 및 관리 수월성능일일 배치 분석에 약 8시간 소요메모리를 활용하여 동일 작업에 약 1시간 소요이렇게 시스템을 재구성하는 작업이 간단치는 않았습니다. 이전 시스템을 계속 부분적으로 운영하면서 점진적으로 재구성 작업을 하였는데 대부분 시스템을 옮기는데 약 1개월 정도가 걸렸습니다. 그리고 기존 시스템을 완전히 대체하는 작업은 약 6개월 후에 종료되었는데, 이는 분석 성능이 크게 중요하지 않은 부분들에 대해서는 시간을 두고 여유 있게 작업했기 때문이었습니다.Spark와 Spark SQL을 활용하여 원하는 데이터를 즉석에서 뽑아내고 공유하는 예제Zeppelin을 활용하여 인기 스티커를 조회하는 dashboard 만드는 예제결론비트윈 데이터 분석팀은 수개월에 걸쳐 데이터 분석 시스템을 전부 재구성하였습니다. 중점을 둔 부분은빠르고 효율적이며 범용성이 있는 Apache Spark, Apache Zeppelin을 활용하는 것최대한 시스템을 간단하게 구성하여 관리 포인트를 줄이는 것두 가지였고, 그 결과는 매우 성공적이었습니다.우선 데이터 분석가 입장에서도 관리해야 할 포인트가 적어져 부담이 덜하고, 이에 따라 Ad-hoc분석을 수행할 수 있는 시간도 늘어나 여러 가지 데이터 분석 결과를 필요로 하는 다른 팀들의 만족도가 높아졌습니다. 새로운 기술을 사용해 본 경험을 글로 써서 공유하고, 오픈소스 커뮤니티에 기여할 수 있는 시간과 기회도 생겼기 때문에 개발자로서 보람을 느끼고 있습니다.물론 새롭게 구성한 시스템이 장점만 있는 것은 아닙니다. 새로운 기술들로 시스템을 구성하다 보니 세세한 기능들이 아쉬울 때도 있고, 안정성도 더 좋아져야 한다고 느낍니다. 대부분 오픈소스 프로젝트이므로, 이러한 부분은 적극적으로 기여하여 개선하여 나갈 계획입니다.비트윈 팀에서는 더 좋은 개발환경, 분석환경을 위해 노력하고 있으며 이는 더 좋은 서비스를 만들기 위한 중요한 기반이 된다고 생각합니다. 저희는 항상 좋은 개발자를 모시고 있다는 광고와 함께 글을 마칩니다.연관 자료: AWS 한국 유저 그룹 - Spark + S3 + R3 을 이용한 데이터 분석 시스템 만들기↩저희는 언제나 타다 및 비트윈 서비스를 함께 만들며 기술적인 문제를 함께 풀어나갈 능력있는 개발자를 모시고 있습니다. 언제든 부담없이 [email protected]로 이메일을 주시기 바랍니다!
조회수 1192

디자이너는 디자인만 하지 않는다.

그래, 로고를 다시 디자인하였다. 그 다음은? 앞서 이야기한 대로 핀다의 새 얼굴을 만들었다. 이제 핀다의 '몸'을 다시 디자인할 차례이다. 경우에 따라 바뀐 로고를 기존 사이트에 그대로 사용하는 경우도 있지만, 이는 바뀐 정도가 아주 미비한 경우에나 가능한 이야기이다. 이런 경우라면 모를까... (출처: 구글) 핀다의 새로운 로고는 기존 로고의 기하학적 요소를 활용하였지만, 외형적인 차이가 크고 로고가 전달하는 이미지도 많은 차이가 난다. 이 경우 기존의 사이트를 활용하는 것은 불가능에 가깝다. 새 로고와 예전사이트를 조합해보았다 - 이상하다껍데기만 바꿀 것인가, 알맹이도 바꿀 것인가?사이트를 개편하는 프로젝트는 새로운 집을 짓는 것이 아닌 기존 집을 리모델링 하는 작업과 비슷하다. 기존의 뼈대 위에 새롭게 바꾼 외장재를 덧붙이는 형식이 많다. 그러나 필요에 따라 쓸모없는 공간을 부수고 다른 공간으로 만드는 것처럼 사이트의 기획도 부분적으로 수정하기도 한다. 물론 기획 수정이 들어가는 경우 더욱 많은 리소스가 필요하므로 전체적인 일정을 고려하여 기획 범위를 정해야 한다. 하고 싶은건 많은데 늘 시간은 부족하다그런데 난 디자이너이지 않나?디자이너가 해야 하는 영역과 기획자가 하는 영역이 있지 각각 있지 않을까? 나도 예전에는 그렇게 일을 했었다. 뼈대를 만드는 사람, 그리고 거기에 예쁜 외장재를 붙이는 사람이 구분된 업무를 진행해 왔다. 내가 준비한 외장재가 어울리는 뼈대를 찾는 게 아니라 그 뼈대에 맞는 외장재를 준비하는 디자이너였다. 그렇게 준비해온 외장재는 마음에 들지 않기 일쑤였고 무엇보다 전달받은 뼈대가 마음에 들지 않았다. 이러쿵 저러쿵 싫다면 둘다 하는 수 밖에 (출처: http://seokjun.kr/why-engineers-become-ceo/)게다가 핀다(Finda)에는 기획자라는 포지션이 따로 있지 않았다. 이렇듯 스타트업의 환경에서는 각 회사와 단계에 맞춰 기존의 포지션이 없기도 하는데, 특히 디자이너가 두 가지 역할을 동시에 해야 하는 경우가 자주 발생한다. 빠른 속도로 효과적인 결과물을 만드는데 가장 필요한 것은 절차의 단순화이고, 이를 가장 잘 소화할 수 있는 포지션이 디자이너라 생각되었다. 즉, 외장재를 붙일 뼈대를 처음부터 세우는 역할은 무엇보다 디자이너가 가장 잘 할 수 있다.그렇게 시작된 기획. 모든 프로젝트가 그렇겠지만 빡빡한 일정을 고려하여 (세상에 일정이 넉넉한 프로젝트는 존재하지 않는다) 다음 몇 가지를 다시 기획하였다.1) 메인페이지말 그대로 얼굴이다. 기회 초기에는 소비자가 가장 처음 보는 화면인 만큼 많은 정보를 한꺼번에 보여주고자 하였다. 그러나 사용성 데이터 분석결과 정성스럽게 준비한 내용을 끝까지 꼼꼼하게 다 보는 사용자는 극히 일부였다. 스마트폰이 이렇게 생기지 않는 이상 사용자가 화면 전체를 다 소화하긴 힘들 것이다. 일반적으로 광고를 돌리거나 이벤트를 진행하는 경우 보통 메인페이지로 랜딩을 시키지 않기 때문에 새롭게 개편되는 메인페이지의 역할은 핀다 사용자들이 필요로하는 정보가 모여있는 최종 목표 페이지, 즉 상품 카테고리별 대표페이지나 상품을 전체적으로 볼 수있는 리스트페이지로 자연스럽게 이동시킬 수 있는 목적을 구현하는 것으로 출발선으로 정하였다. 아울러 우리의 소중한 파트너사들을 위한 광고영역 (스크롤 없이 노출이 가능한 비율을 기준으로 하였다.)도 중요하기 때문에 이 영역도 미리 고려해 두었다.  모바일 화면상 핀다의 메인페이지를 구성하는 배너와 광고 영역의 예2) 메뉴 구성기존 GNB에는 상당히 많은 메뉴가 존재했다. 취급하는 상품이 다양하기에 그만큼 보여주고 싶은 것도 많았었다. 그렇게 하나둘씩 늘어난 메뉴의 가짓수는 그 상품의 목적이 비슷함에도 불구하고 별도의 메뉴로 나누어져 있었고 블로그 콘텐츠도 메뉴의 항목으로 구성되어 있었다. 리브랜딩 전 메뉴구성 (위) vs 리브랜딩 후 메뉴구성 (아래) 이번 리뉴얼에서는 여러 개로나누어진 상품들을 상품의 목적에 따라 카테고리화했다. 돈을 벌기 위한 '투자', 돈을 빌리기 위한 '대출', 그리고 소비를 위한 '카드' 크게 3가지로 나뉘었고, 브랜드관과 블로그를 추가하여 총 5개의 메뉴로 개편하였다. 기존에 있었던 블로그 콘텐츠, 특판상품은 새롭게 추가된 페이지 내부에 배치하여 메뉴 가짓수를 줄일 뿐만 아니라 프로덕트 전체에서 사용성 및 중요도에 따라 계층구조를 체계화시킬 수 있었다.3) 카테고리별 대표 페이지의 추가 상품 형식을 세 가지로 줄이고 각 형식에 해당하는 상품군을 배치하였지만 무턱대고 우리 이런 상품 정보가 있다고 줄줄이 보여주기에는 묶인 단위와 결과값이 너무나 방대하다고 생각했다. 하다못해 마트에서 수많은 물건중 하나를 고르기도 어려운데 금융인들의 일상용어로 꾸며진 상품은 오죽하겠는가... 사용자들이 가장 궁금해하는 일부 우려진 추천상품에 대한 정보 제공 및 자연스럽게 각 하위 상품들로의 연결, 계산기와 맞춤 추천, 나아가 관련 콘텐츠까지 자연스럽게 연결할 수 있는 일종의 허브 역할을 하는 대표 페이지를 새롭게 추가하였다.카드 추천을 위해 기획된 user flow별 실제 화면 (feat. 착착 이렇게만 넘어가면 좋겠는데)  이 페이지들은 메인페이지 -> 상품 메인페이지 -> 상품 목록페이지 -> 상품 상세페이지로 이어지는 플로우를 보다 자연스럽게 만들어 주었으며 다양한 목적의 랜딩페이지로도 활용이 가능하다. 4) 회사 소개 페이지의 상단 이동과거 나이 많은 CEO의 허세 가득한 비전만 담긴 회사소개와 달리 요즘 회사소개 페이지는 그 회사의 문화를 보여줄 수 있는 등 다양한 역할을 가지고 있다.전형적인 기업들의 진부한 CEO 인사말 일반적인 기업들과는 달리 핀다와 같은 스타트업의 경우 회사가 무엇을 하는 것 만큼 회사의 문화, 사람을 알고 싶어 하는 니즈가 더 크기에 기존 꼭꼭 숨어있던 회사소개 페이지를 과감히 상단에 배치하였다. 실제로 과거 사용성 데이터를 보았을 때도 상품 가입 페이지를 제외하곤 메뉴나 페이지 사용성이 매우 높은 페이지 중 하나였다. 회사가 나아가고자 하는 비전도 중요하지만 어떤 경험을 가지고 있는 사람이 모여있는지, 그리고 핀다가 브랜딩에 얼마나 애정을 가졌는지를 보여주고 싶었다. 회사 페이지 내 배치될 비전과 미션, 그리고 팀원들을 정성스레 소개하기 위해서 지난 몇개월간 팀 전체가 고민하며 더 꼼꼼하게 채워나갔고, 일반적으로 카메라를 들이대면 부끄러워하는 우리나라 사람들과 달리 매우 잘 포즈를 취해준 팀원들 덕분에 활기차고 당당한 프로필사진을 촬영하여 그대로 잘 활용할 수 있었다.Thanks to Photoshop and our team새로운 사이트를 이미 오픈한 시점에서 앞서 언급한 것 보다 더 많은 것을 구성했으나 반영하지 못하고 미리 고려해보지 못한 점들이 너무나 많이 있어 아쉽다. (그랬다면 아직도 오픈을 못 했을수도 있다. 명심하자. 프로젝트를 공개하는 것과 공개된 프로젝트를 유지 보수하는 업무 구분은 명확히 해야 한다. 그러지 못할 경우 계속 지연되는 것 밖에 없다.) 이번 글에는 무엇을 목적으로 어떻게 리브랜딩을 기획했는지에 대한 간단한 이야기를 해보았다. 다음 글에서는 좀 더 디자이너답게 프로덕트를 어떻게 꾸며 나가고 있는지에 대해 이야기해 보고자 한다.  #핀다 #디자인 #디자이너 #철학 #브랜드 #브랜딩 #인사이트
조회수 838

협업툴 플로우의 새로운 사무실 … 랜선 집들이 😊

2021년 8월, 플로우팀은 새로운 사무실 공간으로 이사를 했어요. 😉 새로운 사무실은 플로우가 가진 협업 철학을 가득 담아 설계되었는데요! 이 포스팅을 통해 플로우팀의 공간이 어떤 모습으로 변화했는지 소개해드릴게요!플로우 뉴 사무실 투어! 지금 시작합니다.🚗🚀1. 같이 경험하고 성장하는     전사 타운홀 미팅 🚀플로우는 한 달에 한 번 전직원이 모여 그간의 성공담과 실패담을 공유는 📅'월간 경영 포럼' 이라는 특별한 사내 문화가 있어요. 서로의 경험과 고민을 함께 공유하며 자신의 업무 외 다양한 분야에 대한 안목을 넓히는 플로우만의 협업 문화에요! 넓은 타운홀 미팅 공간은 플로우 팀의 전직원 소통을 위한 홀로 꾸며져 더 자유로운 회사 분위기를 연출했어요!2. 뻥 뚫린 회의실에서    자유로운 소통중 🙋‍♀️🙋‍♂️통유리를 활용한 뻥 뚫린 폴딩도어 인테리어가 돋보이는 플로우의 회의실입니다. 덕분에 답답하고 권위적인 분위기를 탈피하고 개방된 의견을 표현할 수 있는 자유로운 회의 공간이 되었어요! 구글 시계로 유명한 '⏲타임타이머'를 활용해서 회의시간을 정해 놓고 집중력 있게 시간 관리를 하고 있답니다! 회의 공간에서 플로우의 팀원들은 자신의 생각을 다른 팀원에게 공유하고 의견을 듣으면서 함께 성장하는데, 그 분위기가 얼마나 즐거운지 직접 경험해 보신다면 놀라실거에요!3. 휴식이 필요할 때 떠나요 ~     플로우 제주도🛫누구나 때때로 일에 집중하기 어려운 날이 있죠. 플로우에서는 그런 날 억지로 책상에 앉아 끙끙거릴 필요가 없어요. 점심 시간 등 쉬는 시간을 모두에게 허용된 휴게 공간에서 무한 힐링🌵하며 다시 집중력을 되찾을 수 있죠! 2층으로된 휴식 침대와 안마의자까지 1인용으로 프라이빗하게 사용할 수 있어요! 휴게실이라는 곳은 시설도 중요하지만 눈치 보지 않아도 되는 편안한 분위기가 정말 중요한데요! 그런 의미에서 플로우 휴게실은 “진짜” 랍니다.* 잠시 글쓴이 맘대로 소개하는 PPL 보고 가겠습니다.수면 전문 브랜드 '삼분의일'에서 플로우팀을 위해 메트리스를 협찬해주셨습니다. 꺄. 💕 딱 10분만 자려고 누웠는데 어젯밤 집 보다 회사에서 더 딥슬립하게 만들어 준다는 소문이...감사 표현에 진심인 편...♥침대와 내가 한 몸이 되는 물아일체의 경지를 느끼고 싶으신 분들이라면.. 삼분의일 4. 플로우가 만들어 지는 곳.      업무 공간 💻출근을 해서 가장 오랜 시간 앉아있는 공간인 업무 공간! 가장 중요하겠죠?팀 별 성향에 맞게 자율적으로 업무 공간을 꾸밀 수 있답니다. 공간'이 사람에게 미치는 영향은 어마어마하다고 해요. 왠지 더 크리에이티브한 상상력이 넘쳐날 것 같다는 기대감이 드는, 플로우의 업무 공간! 또한 개개인이 작업에 완전히 몰두 할 수 있는 넉넉한 개인 책상 공간과 타팀과 분리된 자리 배치로 플로우팀은 더욱 더 발전하고 있답니다!5. 작은 1%까지 마음써주는      배려 공간 🙏어쩌면 다른 회사에서는 창고로 사용되었을 수도 있는 작은 공간들, 플로우에서는 그런 장소까지 직원들을 위한 중요한 공간으로 활용되고 있어요. 공동 휴게실이 부담될 수 있는 여성 직원들을 배려한 여성 전용 휴게실, 업무의 기한을 지키기 위해 집중이 필요한 때 필요한 1인 업무 집중 공간을, 동료들의 집중력을 위한 매너있는 폰부스까지!여기까지 플로우의 새로운 오피스를 소개해드렸어요!플로우는 업무에 100% 몰입하여 역량을 발휘할 수 있는 환경을 만드는데 힘쓰고, 임직원이 함께 얻은 성과를 바탕으로 한 재원을 다시 더 좋은 일터를 만드는데 사용하고 있어요! 앞으로 변화된 사무실에서 더 큰 꿈을 이뤄가는 플로우팀을 지켜봐주세요. 협업툴 플로우 바로가기
조회수 752

숙박앱에 필요한와이즈트래커 리포트 Top 3

숙박앱은 O2O 서비스를 선도하는 사업 중 하나로 빠르게 시장을 확보하기 위한 다수의 앱이 생산되면서, 유사한 경쟁 앱 속에서 차별화 된 서비스로 고객을 잡기 위한 노력이 치열한 사업영역 이기도 합니다. 그래서 숙박 앱 운영에 도움이 될 와이즈트래커의 리포트 3가지를 소개하고자 합니다.1. 상품 카테고리 리포트숙박의 등급은 생각보다 다양합니다. 그러나 숙박 앱에서 한 화면에 보여지는 컨텐츠는 1~2개이며, 이후에는 지속적인 스크롤링으로 원하는 숙박장소를 찾기 때문에 사용자가 선호하는 컨텐츠를 상단에 효과적으로 배치하는 게 중요합니다.상품 카테고리 리포트는 각 숙박 카테고리별로 방문수(=유니크 조회수), 평균 체류시간 등 인게이지먼트 지표와 더불어 객실선택, 예약하기, 주문, 매출액 등 다양한 컨버전 지표를 함께 제공합니다. 나아가 상품 리포트를 통해서 ‘특급’이란 카테고리 중 실제 어떤 호텔이 효과가 좋았는지를 파악할 수 있습니다.이러한 데이터는 컨텐츠 배치 뿐만 아니라, 제휴 영역을 확장하는 데도 어떤 카테고리에 집중해야 할지 참고할 수 있는 유용한 데이터입니다.2. 화면 이동경로 리포트숙박 앱 UI는 매우 심플하고 직관적인 편입니다. 사용자는 예약이 앱 실행의 주 목적이기 때문에, 퍼블리셔는 보통 첫 화면에 컨텐츠를 스크롤링해서 볼 수 있도록 구성하지만 의외로 예약에 접근하는 행동패턴은 다양할 수 있습니다.샘플 데이터처럼 목적을 갖고 검색을 통해 빠르게 상품 정보를 획득하고자 하는 사용자의 비중이 많다면, 모바일 기기에 적합한 내부 검색엔진 편의성 및 결과 화면의 퀄리티가 매우 중요할 것이며 이는 예약율과 직결될 수 있습니다. 반대로 검색했는데 만족하지 못한 결과 값을 제공했다면, 높은 외부 유출 비율을 나타낼 것입니다.화면 이동경로 리포트는 이러한 다양한 사용자들의 행동패턴을 타겟별로 4가지 타입(A화면 이후, A화면 전/후, A화면 도달경로, A화면에서 B화면을 도달하는 경로)으로 분석하여 네비게이션 개선에 통찰력을 얻을 수 있는 데이터를 제공합니다.3. 내부 검색어 리포트 숙박 앱에서 검색엔진을 사용하는 빈도는 꽤 높습니다. 앱을 실행하자마자 검색하는 사용자는 서핑을 즐겨하기보단 자신이 원하는 컨텐츠(정보)만을 빠르게 받고 싶은 성향이 있습니다. 해당 사용자에겐 효과적인 검색결과 화면을 제공하는 것이 핵심입니다.검색결과 화면은 2가지가 필히 고려돼야 합니다.1) 검색결과와 관련성 높은 결과 값 제시( 방대한 결과값은 오히려 재검색하게 하여 불편함을 제공)2) 검색결과 값이 없을 경우 대안을 제시( 빈 페이지 제시는 매우 부정적인 경험으로 기억)내부 검색어 리포트는 사용자의 검색빈도가 높은 인기 키워드를 파악할 수 있으며, 검색 실패수 지표를 통해 온전한 결과 값을 제시하지 못한 경우를 찾아 검색엔진 개선의 방향을 잡을 수 있습니다.

기업문화 엿볼 때, 더팀스

로그인

/