계획대로 서비스를 출시하기 위한 5가지 원칙 – 로켓펀치 팀의 1년간 UX 개편을 돌아보며

[ 왜 UX 개편을 할까요? ]

UX(User eXperience)란 고객이 서비스를 이용하는 과정에서 겪는 경험입니다. 사용자가 서비스를 사용하는 목적에 맞게 필요한 기능을 제공하고 목적을 달성할 수 있도록 서비스 구조를 면밀하게 설계합니다. UX에 개선 요소가 있거나, 기존의 서비스에서 확장된 더 큰 가치를 전달하려는 과정에서 UX 개편을 하게 됩니다.

[ 로켓펀치는 왜 UX 개편을 시작하였나? ]

<로켓펀치>는 스타트업을 위한 채용 서비스로 시작하여 기업, 채용 등 비즈니스 관련 10억 건의 데이터를 축적하며 연간 200만 명 이상이 편리하게 사용할 수 있는 온라인 네트워킹 서비스를 제공했습니다. 이 과정에서 ‘개인 프로필에 더 많은 내용을 입력할 수 있게 해주세요.’, ‘사람을 더 쉽게 찾을 수 있게 해주세요.’ 등 서비스 개선 목소리를 들었습니다. 이를 바탕으로 대한민국 전체 경제 인구에게 필요한 비즈니스 네트워킹 서비스를 제공하기 위해 2017년 말부터 UX 개편 프로젝트를 시작하였습니다.

[ ‘비즈니스 네트워킹 서비스’로 성장하기 위해 필요한 것 ]

개인 프로필과 네트워킹 기능을 강화한 <로켓펀치>를 간단하게 설명하자면 다음과 같습니다.

1. 더 다양한 이야기를 공유하고 상호작용 할 수 있습니다,

▲ 사용자의 정보를 더 쉽게 전달하게 된 <로켓펀치> 홈

경력 사항, 프로젝트 이력 등으로는 표현하기 힘든 이야기를 공유할 수 있도록 게시글을 작성하고 관심있을 정보를 쉽게 조회할 수 있게 홈을 개편하였습니다. 전문가 및 채용 정보, 기업 뉴스 등을 각각 정해진 영역에서 볼 수 있었던 개편 전 서비스 UI(User Interface)에 비해 사용자들이 필요한 정보를 더 쉽게 접하게 되었고 추천, 댓글, 공유 등 상호작용을 원활하게 할 수 있게 되었습니다.

2. 활동 분야 태그와 랭킹을 통해 프로를 더 쉽게 찾을 수 있습니다.


▲ 활동 분야를 나타내는 포인트와 ‘프로’ 뱃지

각 분야별 프로를 더 쉽게 찾을 수 있도록 태그 적용을 확대하고 랭킹 개념을 도입했습니다. 사용자의 활동에 따라 포인트가 쌓이고, 포인트가 높은 사용자는 각 분야별 프로 검색 시 상위에 노출됩니다. 분야별로 상위에 랭킹된 사용자는 ‘프로’ 뱃지도 받을 수 있습니다.

[ UX 개편, 그 시작과 진행 과정 ]

<로켓펀치>의 UX 개편 프로젝트는 2017년 말 시작되어 2018년 11월에 완료되었습니다.
약 1년이 소요된 프로젝트, 어떤 일들이 있었을까요?

▲ UX 개편 과정 중 진행했던 스프린트 모습

먼저 팀원 전체가 함께 모여 홈 개편을 포함한 전체 사이트의 방향성에 대해 의견을 나누었습니다. 큰 그림을 그리는 일부터, 세부적인 정책을 도출할 때까지 함께 회의했습니다.

타겟 고객 이해도를 높이기 위해 사용자 인터뷰도 진행했습니다. 현업 IT 종사자, 창업을 계획하는 예비 스타트업 대표, 창업을 하여 사업을 진행 중인 기업 대표까지 총 3명의 인터뷰를 바탕으로 인사이트를 추출하고, 핵심 컨셉을 설정했습니다.

핵심 UX를 정의하기 위해 5일간 스프린트 워크숍을 열기도 했습니다. 이후 집중해야 할 것들을 정리하고 세부 정책을 만들어가면서 마지막으로 브랜드 및 개편 방향을 재검토하며 UX 개편 준비를 마쳤습니다.

[ 함께 진행된 ‘리브랜딩’ 프로젝트 ]

새로운 UX를 위한 아이디어와 전략을 다듬은 뒤, 리브랜딩 프로젝트를 함께 진행했습니다. 채용 중심의 ‘스타트업 네트워킹 플랫폼’에서 확장하여 ‘비즈니스 네트워킹 서비스’을 명확하게 전달할 수 있는 브랜드 전략을 수립하기 위해 <로켓펀치>는 크리에이티브 솔루션 기업 <슬로워크>와 협업하였습니다.

리브랜딩 프로젝트 바로가기

[ 계획대로 서비스를 출시하기 위한 원칙 5가지 ]

<로켓펀치> UX 개편은 전체적으로 볼 때 약 1년이라는 시간이 걸린 대형(?) 프로젝트였지만, 실제로 디자인/개발 기간은 2개월 정도로 아주 짧았습니다. <로켓펀치>의 브랜드 방향성과 그에 따른 제품 및 서비스 방향에 대한 고민이 길어지면서 [리서치-아이디어-회의-디자인-전면 수정] 과정을 여러번 진행했습니다. 2018년 9월에 개편 방향성이 확정되었고 이 후 본격적으로 디자인과 개발이 시작되었습니다. 실제 개발은 전체 디자인이 나온 10월부터 약 한 달 정도 진행되었고 2018년 11월 1일, 새로운 <로켓펀치>를 세상에 선보였습니다.

오랜 고민과 많은 시행착오 끝에 완료된 <로켓펀치> UX 개편 프로젝트. 팀원들은 어떤 것을 깨달았을까요? <로켓펀치>에서는 UX 개편 완료 후, KPT* 방법을 활용해 팀원 전체가 프로젝트를 리뷰하는 시간을 가졌습니다.

(*KPT 방법론이란? Keep, Problem, Try 의 약자. 다음 프로젝트를 진행할 때도 유지할 것(Keep), 프로젝트를 진행하면서 문제가 되었던 것(Problem), 다음 프로젝트 진행 시 시도할 것(Try)으로 구분지어 회고하는 방법)

<리뷰에 참여한 사람들>

윤유진
PM
@로켓펀치
정예연
제품디자이너
@로켓펀치
지광훈
제품디자이너
@로켓펀치
김동희
CTO
@로켓펀치
김재찬
프로그래머
@로켓펀치
정경훈
프로그래머
@로켓펀치
이상범
CSO
@로켓펀치

1. 서비스 출시 날짜 포함한 세부 일정을 지키려고 노력

이상범 CSO @로켓펀치
“Done Is Better Than Perfect”. 초기 계획했던 서비스 스펙을 조정하는 일이 있더라도 사업 계획에 맞춰 UX 개편을 마친 것이 좋았습니다.

김동희 CTO @로켓펀치
고정된 일정에 맞춰 서비스 스펙을 조정하고, 개발 리소스를 분배하며 진행하여 짧은 시간 내에 성공적으로 서비스를 출시할 수 있었습니다.

지광훈 제품디자이너 @로켓펀치
팀 단위로 일정별로 진행해야 하는 업무를 정의하고, 꼭 지키려고 노력한 덕에 좋은 성과가 있었습니다.

윤유진 PM @로켓펀치
일정을 기준으로 작업할 양을 조정해서 프로젝트 지연 없이 계획한 날짜에 릴리즈할 수 있었습니다.

2. 개발 및 디자인 작업 기간은 신중하게 잡기

윤유진 PM @로켓펀치
작업 기간은 프로젝트 진행 중 발생할 수 있는 다양한 변수를 고려하여 더 신중하게 계획해야 할 것 같습니다. 이번 프로젝트는 서비스 스펙에 비해 디자인 및 개발 작업 기간을 너무 짧게 잡았습니다. 그러다 보니 개발이 완료되기 전 QA를 해야 하는 상황이 발생하기도 했습니다.

김재찬 프로그래머 @로켓펀치
정책이나 디자인은 언제나 바뀔 수 있다고 생각하고, QA까지 고려하여 일정을 잡아야 합니다. 그리고 가능하다면 모듈별로 개발을 좀 더 일찍 시작할 수 있으면 좋겠습니다.

3. 할 수 있는 것부터 효율적 진행해서 시간 낭비 줄이기

김동희 CTO @로켓펀치
이번에는 기획과 디자인을 다 마친 뒤 개발을 시작했는데, 부분적으로 개발을 좀 더 일찍 시작할 수 있었을 것 같습니다. 디자인 쪽에서 전체 파트가 완성되길 기다리는 것보다 중요 파트를 요청하고 진행했으면 시간을 더 효율적으로 사용할 수 있었다고 생각합니다.

정경훈 프로그래머 @로켓펀치
결과론적인 얘기지만 기획과 디자인이 끝나기 전이라도 구현을 시작할 수 있었던 게 더 있지 않았을까 생각합니다.

4. 팀 간 커뮤니케이션을 더 일찍 시작하기

정예연 제품디자이너 @로켓펀치
디자인팀과 기획팀, 개발팀 사이 커뮤니케이션이 아쉬웠습니다. 특히 개발팀과의 커뮤니케이션은 디자인 완성 후 개발이 시작되면 활성화되었는데 좀 더 일찍 시작하면 이후 커뮤니케이션에 필요한 시간을 절약할 수 있었을 것 같습니다.

윤유진 PM @로켓펀치
개발 담당자들이 각 기능들을 더 일찍 리뷰하고 디자이너, CTO, PM 등 관계자와 의견을 공유하는 것이 필요합니다.

김동희 CTO @로켓펀치
초기에 기획팀, 디자인팀, 개발팀이 같이 주요 기능에 대해 같이 논의하여 예상되는 문제점들을 일찍 공유하면 더 효율적으로 프로젝트를 진행할 수 있을것 같습니다.

5. 효율적인 업무 진행에 필요한 도구 적극적으로 활용하기

정예연 제품디자이너 @로켓펀치
기존에 원격으로 업무를 진행하면서 불편하다고 느꼈던 디자인 논의와 디자인 자료 공유가 ‘인비전 프리핸드’ 활용으로 많이 개선되었습니다.

김재찬 프로그래머 @로켓펀치
계속 업데이트 되는 정책서 변경 사항을 파악하기가 어려웠습니다. 수정된 사항들을 쉽게 파악할 수 있게 새로운 도구를 써보는 것이 어떨까 합니다. (Git + Markdown 등)
큰 프로젝트를 진행하다보니 각 기능별 디자인 파일을 찾기가 어려웠습니다. 파일 관리 규칙을 정하거나 적절한 도구를 활용하여 개선할 수 있을것 같습니다.

정경훈 프로그래머 @로켓펀치
현재 스펙 문서 도구로 Google Docs를 쓰고 있는데, 특정 날짜 기준으로 전후 수정 사항을 쉽게 보기 힘들었습니다. 적절한 도구를 활용하면 효율적으로 개발 진행을 할 수 있을것 같습니다.

[ 로켓펀치의 약속 ]

<로켓펀치>는 경제 인구가 일하면서 겪는 어려움을 해결하기 위해 끊임없이 진화하고 있습니다. 2013년, 스타트업의 채용 문제를 해결하기 위해 서비스를 시작하여 이제는 대한민국 경제 인구를 위한 비즈니스 네트워킹 서비스를 목표로 합니다. 신뢰할 수 있는 경험 정보를 나누고, 폭넓은 비즈니스 교류가 활성화되는 것, 이때 핵심은 바로 사람과 사람 간 연결입니다. 이 연결을 보다 편하고 자연스럽게 이어나갈 수 있도록 <로켓펀치>는 고객의 목소리에 귀기울이고 더 좋은 서비스를 제공하도록 꾸준히 노력하겠습니다.

‘머신러닝?’ 잘 알려줄 것 같은 현직 개발자들

머신러닝을 활용하기 위해서 궁금한 것들이 있을 때, 이분들께 물어보는 건 어떨까요?

머신러닝 잘 알려줄 것 같은 현직 개발자들

 

전무익 당근마켓 소프트웨어엔지니어

전무익 당근마켓 소프트웨어 엔지니어

“서비스 개발하는 재미로 살아가는 자연인ㅎ”

전) 카카오, 띵크리얼스

연락하기 >> https://www.rocketpunch.com/@muik

 

오영민 네오펙트 데이터사이언티스트

오영민 네오펙트 데이터 사이언티스트

“사람과 기계의 지능학습을 연구하는 뇌과학자, 데이터 사이언티스트, 인공지능 연구자입니다”

연락하기 >> https://www.rocketpunch.com/@youngminoh7

 

소성운 어반베이스 ML / Data Science

소성운 어반베이스 ML / Data Science

“Data Scientist”

전) 채팅캣, LG전자

연락하기 >> https://www.rocketpunch.com/@yanso

 

김범수 스캐터랩 머신러닝팀

김범수 머신러닝팀

“딥러닝/머신러닝 엔지니어입니다.”

연락하기 >> https://www.rocketpunch.com/@aab33316cb88432d

 

로켓펀치에서 더 많은 머신러닝 전문가를 만나고 싶다면 >> 바로가기

AWS 람다(Lambda)로 실시간 추천하기 – 로켓펀치의 전문기술 정보

로켓펀치의 전문기술 정보

로켓펀치에는 다양한 종류의 비즈니스 정보들이 있습니다. 홈페이지를 보면 상단 네비게이션 바의 네트워크, 기업, 채용, 투자, 비즈니스 맵 등이 상위 항목 정보로서 여러 가지 또다른 세부 정보를 가지고 있는 것을 알 수 있습니다. 이 중에서도 사람과 기업, 채용정보는 전문기술 정보를 포함하고 있는데 이는 이용자가 각 항목에서 알고 싶은 내용들을 나타내고 있습니다. 우리가 어떤 사람이나 기업에 대해서 ‘이 분은 어떤 걸 잘 하는 걸까?’, ‘여기서 사용하는 기술들은 뭐지?’와 같은 궁금증을 가지는 것은 자연스러운 일입니다. 구인을 하는 기업 입장에서 어떤 기술을 가진 사람을 원하는지 나타내는 것도, 구직을 하는 입장에서 기업이 어떤 스킬을 가진 인재를 원하는지 알아야 하는 것도 당연합니다.

전문기술의 특징

전문기술은 다른 정보와는 조금 다른 특징을 가지고 있습니다. 개인의 경력이나 기업의 이력과 같은 정보들은 각 항목이 변하지 않는 사실을 담고 있으며 여러 가지 항목의 중요도 또한 큰 차이가 없습니다(정말 알리고 싶지 않은 사실이 있다면 이야기가 다르겠지만요). 반면에 이 전문기술이라는 정보는 그 시점과 환경에 따라 각 항목의 중요도가 달라집니다.

어떤 개발자가 자신의 전문기술 항목을 채워넣을 때를 생각해보겠습니다. 이 사람은 아마도 현재 자기가 주로 다루는 프로그래밍 언어를 입력할 겁니다. 그리고 여러 가지 라이브러리와 주로 사용하는 도구 및 서비스를 추가로 입력할 수 있겠죠. 이 때 고민거리가 생길 수 있습니다.
첫 번째는 환경이 변하는 경우입니다. 이직을 한 직후 사용하는 언어와 개발 환경이 바뀐 경우 개인정보에서 이를 수정해야 할 수 있습니다. 경력이 오래 되어 더 이상 사용하지 않게 된 기술들이 생긴 경우 그것들이 자신을 나타내는 정보라고 보기에도 석연치가 않습니다. 마찬가지로 수정이 필요합니다.
두 번째는 항목 간의 상대적 중요도 차이가 생기는 경우입니다. ‘사용할 줄은 아는데 이걸 굳이 쓰는 게 맞는 걸까? 그렇다고 빼자니 아쉽고…’ 와 같은 고민은 경험한 기술들이 많으면 많을수록 느끼기 쉽습니다. 이럴 때는 여러 가지 전문기술들 중에서 선택을 해야합니다. 기업 또한 이와 같은 일들이 생길 수 있습니다.

이와 같은 문제 때문에 전문기술 정보를 입력한다는 것은 다른 정보와 비교해 상대적으로 어려운 면이 있습니다. 하지만 위에서 말했듯이 전문기술 정보는 상당히 중요한 정보입니다. 이용자가 이를 잘 입력할 수 있도록 도와줄 수 있다면 입력하는 사람에게도 그 정보를 보는 사람에게도 많은 도움이 될 것입니다. 어떻게 하면 더 잘 입력하게 할 수 있을까요?

첫 번째 방법

많이 입력할 것 같은 전문기술들의 목록을 입력란 바로 아래에 나열해 놓고, 클릭하면 입력이 되도록 했습니다. 실제로 이용자들이 입력한 것들을 세어보면 어떤 것들이 있는지 금방 알 수 있습니다. Python, Linux, AWS, UI/UX 등등이 있겠죠. 하지만 이 방법은 명확한 한계가 있습니다. 자주 나오는 전문기술을 가진 이용자들은 쉽게 입력을 할 수 있겠지만 그렇지 않은 경우는 이 방법의 혜택을 받을 수 없습니다. 여러 가지를 입력해야 하는 경우 전부 목록에 있으면 좋겠지만 그렇지 않은 경우 자칫 입력을 빠뜨릴 수 있기도 합니다.

두 번째 방법

이용자가 입력한 전문기술들을 바탕으로 다음에 입력할 것을 추천해 줄 수 있다면 가장 좋을 것이라고 생각했습니다. 바로 아래와 같은 모습으로요.

  1. 첫 번째 예시
    specialty-recommendation-example1
  2. 두 번째 예시
    specialty-recommendation-example2

Collaborative Filtering

위와 같은 경우에 사용할 수 있는 추천 기법은 collaborative filtering이 있습니다. 간단히 말해  “X를 좋아하는 사람은 대개 Y를 좋아합니다. 당신은 X를 좋아하시죠, Y는 어떠십니까?” 라는 방식과 비슷합니다. 이용자가 있고 각각의 이용자들이 좋아하는 아이템들의 목록이 있을 때 제일 먼저 아이템 간의 유사도를 구합니다. 아이템 개수가 N일 때 N*N 행렬로 각 아이템 간의 유사도를 나타낼 수 있습니다. 임의의 아이템들이 주어졌을 때 이 행렬을 이용해 가장 유사한 아이템이 어떤 것인지 쉽게 계산할 수 있습니다. 아래와 같은 유사도 행렬이 있다고 해보겠습니다.

specialty-recommendation-similarity-matrix
다섯 개의 아이템(i1, i2, …, i5)이 있을 때 각각의 유사도를 나타낸 행렬입니다. 유사도는 0과 1사이의 값을 가진다고 가정했습니다. i1과 i2는 0.9로 상당히 비슷하다고 할 수 있습니다. 반면 i3과 i5는 0.1로 낮은 유사도를 가지고 있습니다. 이 때 어떤 사람이 i1과 i2를 좋아한다고 가정해보겠습니다. 이 사람이 선택한 i1과 i2를 가지고 다른 아이템을 추천할 수 있습니다. i1의 유사도 row는 (1, 0.9, 0.2, 0.3, 0.8)입니다. i2는 (0.9, 1, 0.4, 0.5, 0.8)이죠. 단순히 이 둘을 더하면 (1.9, 1.9, 0.6, 0.8, 1.6)이 됩니다. i1과 i2는 이미 골랐으니 가장 높은 값을 가지는 아이템은 i5입니다. 간단하게 이런 방법으로 추천을 할 수 있습니다.

로켓펀치에서는 유사도 행렬을 계산하는 부분과, 그 행렬을 가지고 아이템을 추천하는 부분 크게 두 가지로 나누어 개발했습니다. 처음에는 이 두 가지가 모두 웹서버에 모듈로 붙어 있었습니다. 여러 가지 이슈 때문에 이를 분리해서 AWS Lambda로 옮기기로 했습니다. 비정기적으로 일어나는 task를 처리하기 위해 서버 자원을 항상 실행하고 있을 필요가 없다는 점 외에도 여러 가지 장점이 있습니다(또 다른 사례 및 자세한 내용은 이 글을 참고하시면 좋습니다). 잘만 분리한다면 꽤 괜찮은 선택이 될 것 같았고, 큰 문제없이 분리가 되었습니다. 그런데…

문제 발생

AWS Lambda는 한 번 실행이 되면 그 때부터는 초기 리소스 로딩 비용이 없이 계속 호출이 되는 특징이 있습니다. 그리고 주기적으로 초기 시작을 하는데, 이 초기 시작 때 행렬을 가져와서 메모리에 올리는데 시간이 너무 오래 걸리는 것이었습니다. 이용자가 입력했을 때 즉시 계산을 완료해 입력 칸 아래에 추천을 해야 하는데 이것이 수십초씩 걸리는 것은 안 될 말입니다. 메모리에 올리는 것 그 자체도 문제였죠. AWS Lambda는 사용한 메모리와 실행 시간에 비례해 요금을 내야하기 때문입니다.

해결 방법

처음에 웹 서버에 실행하는 것을 생각해 유사도 정보를 메모리에 올린 것인데 접근 방법을 조금 다르게 할 필요가 있었습니다. 해결 방법은 생각보다 복잡하지 않았습니다. 사실 추천 과정에서 모든 전문기술의 유사도를 가지고 있을 필요는 없습니다. 바로 입력 칸에 있는 전문기술들과 다른 전문기술의 유사도 목록, 즉 커다란 행렬에서 row만 있으면 됩니다. 위 유사도 행렬 예시에서 알 수 있듯이, 유저가 고른 아이템이 i1, i2 뿐이라면 그 두 아이템의 유사도 row만 있으면 계산이 가능합니다. 이해를 돕기 위해 아래에 그림과 단순화한 코드를 첨부했습니다.

specialty-recommendation-memory-usage

# 개선 전
similarity_matrix = get_similarity_matrix() # 커다란 매트릭스를 메모리에 올리는데 상당한 시간과 서버 자원을 사용
for _id in user_input:
    result += similarity_matrix[_id]

# 개선 후
for _id in user_input:
    result += get_row_from_redis(_id) # 계산에 필요한 row만 가져와서 사용

이러면 N*N의 메모리를 사용하던 것을 k*N(k는 최대 수십 개 정도)의 공간만으로 해결할 수 있습니다. 각각의 row를 elasticache(redis)에 저장한 다음, 호출이 있을 때마다 필요한 row를 불러 간단하고 빠르게 계산을 마칠 수 있습니다. 입력한 전문기술 숫자만큼 redis 호출을 해야 하지만 실제 서비스가 되는 과정에서 평균 호출 시간이 100ms 미만임을 확인했습니다. 이 정도면 괜찮은 수준입니다.

마치며

간단한 알고리즘을 로컬에서 실행해 결과를 보는 것과 실제 서비스에 적용하는 것의 간극을 극복하고, 변하는 환경에서 일어나는 문제들을 해결하는 것이 바로 소프트웨어 엔지니어가 하는 일입니다. 로켓펀치는 멋진 이용자 경험을 제공하기 위해 데이터 분석을 통한 각종 기법들을 서비스에 적용할 예정입니다.

+ 로켓펀치를 함께 만들어 갈 인재들을 기다리고 있습니다.

 

– 글쓴이 : 로켓펀치 머신러닝 엔지니어 정희동

300원에 200만뷰 소화하기 – 서버리스 아키텍처 AWS 람다(Lambda) 활용 사례

 

로켓펀치에서는 기본적인 웹 서비스 외에 제휴를 통해 로켓펀치의 채용 공고를 위젯 형식으로 노출하는 경우가 있습니다. (예 : 플래텀 오른쪽 사이드바 위젯) 이런 위젯들을 운영하다 보니 몇 가지 추가적인 요구 사항이 생겼는데요. 주로 아래의 두 가지로 요약할 수 있습니다.

  • 제휴를 맺은 곳의 갑작스러운 트래픽 증가가 로켓펀치 웹 서비스에 영향을 주지 않을 것
  • 로켓펀치에서 일시적인 오류가 발생하더라도 제휴를 맺은 곳에서 가능하면 오류가 발생하지 않을 것

이 두 가지를 만족하기 위해 최초에 기존의 서버와 분리하여 별도의 서버를 구축하는 방안을 생각했습니다. 다만 이 서버를 구축하고 유지하는 여러 가지 비용의 문제로 쉽사리 진행되지 않고 있었습니다. 그러던 중 로켓펀치에서는 AWS Lambda를 통해 이를 손쉽게 구축할 수 있다는 것을 알았고 다음과 같은 이점을 기대할 수 있었습니다.

  • 서버리스 아키텍처(Severless Architecture)를 통해 서버의 배포 및 유지에 대한 비용을 대폭 감소
  • 필요할 때만 노출되기 때문에 불필요한 자원을 소모하지 않음
  • 기존의 서버와 분리하여 혹시 모를 트래픽 증가에 기존의 서버가 영향받지 않음

AWS Lambda는 더욱 많은 장점이 있으나 위에 언급된 내용만으로도 저희가 원하던 것을 손쉽게 얻을 수 있었기 때문에 큰 고민 없이 기존의 채용 공고 위젯을 AWS Lambda로 옮기는 것을 결정했습니다.

Zappa – Serverless Python

AWS Lambda로 채용 공고 위젯을 옮기는 것을 결정하고 몇 가지 고민 끝에 최종적으로 Zappa를 사용하기로 했습니다. Zappa는 Python 기반으로 AWS Lambda를 손쉽게 사용할 수 있게 하고 거기에 더해서 API Gateway까지 자동으로 설정해주어서 최종적으로 저희가 원하는 웹 서버를 간단하게 구축할 수 있는 도구입니다. 물론 원래 AWS에서 제공하는 것처럼 필요한 파일들을 압축하여 업로드하고 관련된 내용을 CLI 또는 웹 콘솔을 통해서 설정하여 구현할 수 있지만, 디버깅, 환경 설정, 배포 등의 이유로 프레임워크를 사용하는 게 좋습니다. Zappa 이외에 사용 가능한 서버리스 프레임워크는 다양하게 있습니다.

  • Serverless: 가장 유명하고 제공하는 기능이 많습니다. 문서화도 잘 되어 있는 편이고 Node.js, Python, Java, Scala를 지원합니다.
  • Apex: express.js를 개발한 TJ Holowaychuk이 만든 프레임워크. 배포 시 멱등성을 보장하며 가장 다양한 언어를 지원합니다. Node.js, Golang, Python, Java, Rust, Clojure를 지원합니다.
  • Chalice: AWS에서 개발한 프레임워크. Python을 지원하며 AWS Lambda와 API Gateway를 자동으로 설정해줍니다.

위의 프레임워크 외에도 더 많은 것들이 있으나 저희는 아래와 같은 이유로 Zappa를 사용하는 것으로 결정했습니다.

– 위에서 언급한 데로 API Gateway까지 설정을 해주기 때문에 배포 후 바로 웹에서 확인 가능합니다.
– 저희는 이미 Django 와 Flask를 사용 중이고 바로 활용할 수 있습니다. 이는 디버깅도 기존에 사용하던 방식을 거의 그대로 사용할 수 있음을 의미합니다. Zappa로 개발 시 실제로 구축된 내용 중 일부는 기존의 내용을 거의 그대로 사용하여 큰 변경 없이 개발이 진행되기도 했습니다.
– C 확장 패키지들을 바로 사용 가능합니다. (AWS Lambda에서 Python을 사용하는 경우 C 확장 패키지들은 반드시 Amazon Linux에서 컴파일된 파일을 사용해야 합니다. 이런 부분이 개발 및 배포 시 불편할 수 있는데 Zappa에서는 이를 미리 컴파일된 파일을 자동으로 가져와서 배포 시 사용합니다)
– 재 수행 시 수행 시간을 느리게 만드는 원인 중 하나인 Cold Start를 방지할 수 있습니다. (설정 시 기본적으로 4분에 한 번씩 호출. 다만 저희는 그렇게 오랫동안 호출되지 않을 일이 없어서 최종적으로는 사용하지 않았습니다)

개발 및 AWS Lambda에 배포하기

Zappa로 개발하는 것은 아주 간단했습니다. 저희가 사용하던 내용 중 채용 공고 위젯의 내용을 일부 가져와서 동일하게 구현(Flask로 구현)하고 같은 개발 환경에서 테스트까지 완료되면 `zappa_settings.json` 파일만 설정하고 배포할 수 있습니다. 여기서는 `zappa_settings.json`에서 설정 가능한 일부 항목들만 간단히 소개하겠습니다.

{
  // API Gateway에서 사용하는 Stage 명입니다.
  "name": {
    // 배포 시 Zip 파일을 업로드할 S3 bucket의 이름입니다.
    "s3_bucket": "bucket-name",
    // 사용할 AWS Region을 설정합니다. 설정 전 반드시 AWS Lambda, API Gateway 그리고 CloudFormation이 올바르게 사용 가능한지 확인해야 합니다.
    // 작년까지 Seoul Region에서는 AWS Lambda, API Gateway는 올바르게 사용 가능하나 CloudFormation을 통해서 API Gateway를 설정하는 데 문제가 있었기 때문에 배포가 올바르게 진행되지 않았습니다.
    "aws_region": "ap-northeast-2",
    // WSGI 애플리케이션 함수. Flask, Django 등에 따라서 내용이 다릅니다. zappa init으로 보통 자동 설정됩니다.
    "app_function": "app.app",
    // Django 로 개발 시 사용되는 Django setting 파일의 위치입니다.
    "django_settings": "your_project.settings"
    // 배포 시 압축 파일에 포함되지 않을 내용을 설정합니다.
    "exclude": ["*.gz", "*.rar", ".git", ".gitignore"],
    // 배포 시 설정될 환경 변수입니다. `os.environ.get`으로 애플리케이션 내에서 간단히 사용 가능합니다.
    "environment_variables": {"your_key": "your_value"},
    // true로 설정 시 자동으로 CloudWatch 이벤트를 추가하여 Cold Start를 방지합니다.
    "keep_warm": true,
    // AWS Lambda에서 사용할 메모리 크기를 결정합니다. AWS Lambda 비용을 결정하는 가장 큰 요소 중 하나입니다.
    "memory_size": 128,
    // AWS Lambda 함수가 수행을 완료할 수 있는 최대 시간을 설정합니다.
    "timeout_seconds": 30,
    // AWS Lambda에 VPC를 설정합니다. 이를 통해 AWS 내의 다른 자원에 대한 접근이 가능합니다.
    "vpc_config": {
      "SubnetIds": ["subnet-12345678"],
      "SecurityGroupIds": ["sg-12345678"]
    }
  }
}

위 내용을 설정 후 Zappa의 deploy(또는 update) 명령어를 사용하는 것으로 배포가 완료되었습니다.

Calling update for environment name..
Downloading and installing dependencies..
100%|██████████████████████████████████| 39/39 [00:10<00:00, 5.27pkg/s]
Packaging project as zip..
Uploading file.zip (11.0MiB)..
100%|██████████████████████████████████| 11.5M/11.5M [00:00<00:00, 21.1MB/s]
Updating Lambda function code..
Updating Lambda function configuration..
Uploading template.json (2.8KiB)..
100%|██████████████████████████████████| 2.83K/2.83K [00:00<00:00, 37.0KB/s]
Deploying API Gateway..
Your deployed Zappa deployment is live!: https://abcd1234.ap-northeast-2.amazonaws.com/name

배포 후에는 url을 통해 바로 확인할 수 있으며 수정이 필요한 경우 수정 후 `zappa update {name}`을 통해 바로 업데이트할 수 있습니다. 저희가 실제로 배포하여 사용 중인 내용 중 하나는 https://widget.rocketpunch.com/banner로 Custom Domain과 SSL을 추가로 설정하여 배포하였으며 언제든 바로 확인할 수 있습니다. AWS Lambda를 사용하기로 하고 약 3일간의 작업을 통해서 개발 및 배포까지 완전히 끝낼 수 있었으며 아래에 기술되는 내용과 더불어 아주 큰 효과를 볼 수 있었습니다.

개발 완료 후

위에 언급한 것 이외에도 AWS Lambda 사용 시 추가적으로 기대하던 것이 하나가 있었습니다. 그것은 비용 절감입니다. AWS Lambda는 자원을 사용한 만큼 지불하기 때문에 저희가 사용 중인 간단한 위젯 화면의 경우는 자원을 매우 적게 사용하기 때문에 요청이 많더라도 일반적인 서버 구축과 비교하면 비용이 매우 적을 것으로 기대했습니다.
실제로 최근 한 달간 193만 Request가 있었고 이때 AWS Lambda의 비용은 $0.19였습니다. 이는 한화로 단돈 300원에 해당합니다.

추가로 API Gateway까지 사용한 금액은 총액 $6.95로 약 8,000원에 월 200만뷰 가까이 소화하는 것을 확인했습니다.
이는 기존의 간단한 서버 구축을 위해서도 사용되는 월 몇만 원의 비용, 트래픽이 몰리는 경우 자원 사용의 문제, 거기에 더해 서버 관리를 위해 소모되는 시간까지 생각하면 아주 적은 비용으로 원하는 내용을 모두 만족하게 되었습니다. 로켓펀치에서는 현재 채용 공고 위젯 외에 비동기로 수행되는 내용의 일부를 AWS Lambda를 사용하여 구현 중이며 기대만큼의 효과를 거두고 있어 앞으로 그 활용 영역을 더욱 넓힐 예정입니다.

J커브 성장을 위한 나침반, ‘서비스 통계 대시보드’ 개발기

‘수억 명의 사용자’ 같은 거대한 목표는 ‘감’으로는 결코 달성할 수 없다

각자가 만들고 있는 제품의 특성에 맞는 올바른 지표(Metric)를 선택하고, 그 지표를 꾸준히 개선해 나가는 것은 J 커브 성장을 달성하기 위한 가장 핵심적인 활동이다. 문제를 모르면 개선할 수도 없기 때문이다. 그런데 이런 고유한 지표를 확인하는 것 자체가 어렵다면 실제 업무에 있어서 활용도가 크게 떨어지기 때문에, 클릭 한번에 확인할 수 있는 ‘대시보드’를 만드는 것이 좋다.

이 활동의 중요성을 알고 있는 로켓펀치는 많은 노력을 들여 로켓펀치만의 지표를 구성하고 쉽게 확인할 수 있는 대시보드를 구성했다. 이 글에서는 그 과정에서 얻었던 지식들을 나누고자 한다.

대시보드 구상 단계

대시보드의 실제 개발에 앞서 실무적으로 고려해야 크게 두 가지다. ‘어떤 데이터를 보여줄 것인지’와 ‘어떤 시간 단위를 사용할 것인지’에 대한 결정이다.

보여줄 데이터에 대한 결정

로켓펀치는 사용자가 생성한 데이터를 재가공하여 또 다른 사용자들과 연결해 주는 ‘사용자 참여형 콘텐츠 플랫폼’이다. 이런 특성을 가지는 서비스의 성장에 가장 중요한 것은 사용자들을 점점 더 서비스에 많이 참여하도록 하는 것이다.

예를 들어 우리가 게시판 기반의 커뮤니티 서비스를 만들고 있다면, 회원 가입 없이 글만 읽던 사용자를 회원 가입을 하게 하고, 글을 쓰게 만드는 것이 참여 수준을 높이는 것이다. 작성되는 글(=콘텐츠)이 많아질 수록 더 많은 사람들이 그 글을 보기 위해 우리 서비스에 방문할 것이기 때문이다.

로켓펀치에는 회원가입 없이 다른 사용자들의 프로필이나 기업 정보, 채용 정보를 보는 ‘방문자’들이 있고, 본인의 프로필을 상세히 업데이트하고 기업 정보와 채용 정보도 기재하는 ‘회원’들이 있다. 로켓펀치가 올바른 방향으로 나아가고 있는지는 방문자들이 회원으로 전환되는 비율을 통해서 알 수 있으므로, 대시보드는 한눈에 사용자들의 ‘참여 수준’을 볼 수 있는 항목들로 구성이 되어야 한다.

예를 들면 아래와 같은 항목들을 한눈에 확인할 수 있는 funnel 분석 그래프를 대시보드에 표시하는 것이다.

– 전체 방문자 수

– 전체 방문자 수 대비 재방문자의 비율

– 전체 방문자 수 대비 회원 가입을 한 비율

– 회원 가입자 중에서 프로필을 상세히 업데이트 한 비율

데이터 처리 시간 단위에 대한 결정

데이터를 대시보드에 표시함에 있어서 ‘시간 단위’는 아주 중요한 요소다.

예를 들어 우리가 ‘메시징 플랫폼’을 만들고 있다고 가정해 보자. 메시징 플랫폼이 사람들에게 제대로 가치를 주고 있다면, 당연하게도 사람들이 하루에도 여러 번 사용해야 한다. 그런데 어떤 외적인 문제가 발생하여 사람들이 하루에 수회 이상 사용하던 경향이 1주에 수회 사용하는 것으로 바뀌어 가고 있다고 생각해보자. 이는 분명 커다란 문제이며 반드시 대응을 해야 한다. 그런데 통계 데이터를 주 단위로 설정해서 보고 있다면, 이런 변화를 인지하기는 어렵다. ‘주’를 단위를 잡았을 때는 그 주에 그 제품을 한 번이라도 사용했다면 ‘활성 사용자’로 표시가 되므로 일 수회 쓰 던 경향이, 주 수회 쓰는 경향으로 바뀌더라도 데이터 상으로는 변화가 없는 것이다. 매일 쓰는 것이 중요한 서비스라면 시간 단위는 ‘주’가 아니라 ‘일’이어야 한다.

다른 예로 ‘여행 상품 제공 플랫폼’을 생각해보자. 우리가 만들고 있는 서비스가 제대로 동작하고 있다면, 사용자가는 얼마 간 여행 상품 구매 활동을 한 후 우리 서비스를 잠시 떠나야 한다. 여행 과정이 완료되었기 때문이다. 일반적인 경제 활동 인구들은 휴가에 맞춰서 일년에 여행을 2~3번 정도 떠나기 때문에, 우리가 만드는 서비스를 통해 여행 상품 구매 활동에 일주일 정도를 쓰고 여행을 다녀온 후, 몇개월이 지나 다시 접속해서 여행 상품을 구매 하는 패턴은 지극히 자연스러운 경향이다. 그런데 이런 서비스를 ‘주’ 단위로 분석한다면 어떻게 될까? 아주 단순화시킨다면, 1주차의 활성 사용자가 2주차부터 24주차(=6개월)까지는 모두 0으로 표시될 것이다. 서비스는 제대로 동작하고 있음에도 불구하고 말이다. 따라서 사용자가 1년에 한두 번 사용해도 충분한 가치를 느낄 수 있는 서비스라면 데이터 분석의 시간 단위는 최소한 월 단위 이상, ‘월, 분기, 반기’ 등이 되어야 할 것이다.

로켓펀치는 스타트업 채용 정보 제공 플랫폼에서 개인과 기업이 비즈니스의 성장에 필요한 다양한 정보를 얻을 수 있는 네트워킹 플랫폼으로 진화하고 있다. 우리는 로켓펀치가 사용자들이 적어도 일주일에 한번씩은 접속하는 서비스가 되어야 한다고 생각하기 때문에, 데이터를 처리하는 기본 시간 단위를 ‘주’로 잡았다.

대시보드 구현 단계

구현 목표와 로켓펀치의 현황, 그리고 방향

필자(=정희동)가 로켓펀치에 합류하는 과정에서 접했던 로켓펀치의 큰 목표 중 하나는 ‘이용자 분석을 제대로 해 보고 싶다’는 것이었다. 매우 흥미로운 과제라고 생각했다. 이용자 분석을 바닥부터 할 수 있는 기회는 그리 흔치 않고, 많은 것을 할 수 있을 것이라 생각했기 때문이다. 구체적으로 이용자들이 얼마나 들어와서 어떤 행동을 하는지 funnel 형태로 보고 싶고, 각각의 행동에 어떤 이유가 있는지 알고 싶었다.

합류 후 곧바로 시스템에 대한 파악을 시작했다. 로켓펀치 웹 서비스의 로그는 Elasticsearch의 제품군들을 비롯한 몇 개의 도구들을 이용해서 저장되고 있었다 (상세 내용은 아래에 설명).

이용자 식별과 이용자들의 행동에 대한 정의를 마친 후 간단한 결과를 빠르게 내는 방향으로 작업을 시작했고, 앞으로의 분석에 걸림돌이 될 부분들을 빠뜨리고 넘어가지 않도록 주의를 기울였다.

기간의 정의

앞서 언급된 이유에 따라 데이터의 기본 지표는 일주일 단위로 생성하기로 했다. 또 로켓펀치 팀에서는 보통 일주일 단위로 새로 추가되거나 개선된 기능을 릴리즈 하기 때문에 일주일이라는 단위는 기본 단위로 적절하다고 생각되었다. 그리고 매주 지표를 생성해서 최근 12주를 비교하기로 했다.

이용자의 행동

정의한 행동은 크게 보았을 때 아래와 같다.

1. 회원 가입

2. 개인정보 입력

3. 사진 등록

4. 학력 및 경력 추가

5. 자기 소개 수정

6. 친구 추가 및 친구 수락

로켓펀치 웹 서비스를 이용할 때 이루어지는 위 행동들은 서로 다른 API 요청 경로(path of request for API)를 가진다. 그리고 해당 로그는 인코딩된 유저 식별자와 함께 저장되므로 로그인 후 어떤 행동을 했는지는 저장된 로그를 이용자별로 모아서 request path를 보는 것만으로 알 수 있었다.

로그가 저장되는 방식

현재 로켓펀치의 로그는 몇 가지 툴을 사용해 아래와 같은 방식으로 저장되고 있다.

1. 웹 서버 디스크에 로그가 저장됨

2. filebeat가 디스크의 로그를 읽어 별도 서버의 redis로 보냄(이 때 redis는 queue처럼 동작함)

3. redis와 같은 서버의 logstash가 redis에 저장된 로그를 읽어 별도 파일로 저장하고, elasticsearch의 인덱스에도 저장함

4. kibana에서 elasticsearch에 저장된 로그를 살펴볼 수 있음

아래는 elasticsearch에 저장된 로그의 모습이다(일부 항목만 표시).

{
“_index” : “rocketpunch”,
“_type” : “logs”,
“_id” : “AVlfyGjraKOw-4GiFG_H”,
“_source” : {
“offset” : 42279229,
“content_length” : “105455”,
“latency” : “0.303436994553”,
“user_id” : “—-“,
“timestamp” : “2017-01-02T15:24:43.584033Z”,
“ip” : “—–“,
“response_code” : “200”,
“referer” : “https://www.rocketpunch.com/,
“user_agent” : “Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36”,
“request_id” : “—–“,
“path” : “/api/users/network_request”,
“method” : “GET”,
}
}

이용자별 로그 모아보기

elasticsearch에 저장된 로그는 kibana에서 찾아보기 아주 편하지만, 검색 결과를 원하는 모양으로 만들고 싶다면 결국 query를 사용해야만 했다. elasticsearch에서 공식적으로 지원하는 언어별 client가 몇 가지 있는데, 익숙한 python을 쓰기로 했다. 사실 이 결정을 내리기 전에 bulk api를 써봤는데, 속도가 꽤 느린데다 대용량 처리 중 오류가 나기도 했다.

1주일 동안의 로그를 읽어 아래와 같은 모양으로 만든다.

이용자 식별자, 시간, 행동, … (나머지 정보들)

이용자 식별자와 시간으로 정렬하면 하나씩 읽어 유저가 어떤 행동을 했는지 알 수 있다. 아래는 그 예시이다.

user_1 2017-01-02T18:58:57.356091Z REG
user_1 2017-01-02T18:59:11.388345Z DET
user_1 2017-01-02T19:04:08.287961Z CAR
user_1 2017-01-02T19:05:10.746819Z CAR
user_1 2017-01-02T19:06:28.057567Z CAR
user_1 2017-01-02T19:08:47.662613Z CAR
user_1 2017-01-02T19:12:04.052667Z EDU
user_1 2017-01-02T19:12:26.961197Z EDU

user_1은 회원 가입(REG) 직후 개인 정보를 입력했고(DET), 몇 가지 경력사항(CAR)과 학력사항(EDU)를 입력했다. 이처럼 간단하게 유저의 행동을 살펴볼 수 있고 원한다면 행동 패턴을 더 정의하고 다른 정보를 결합해 더 상세한 행동을 관찰할 수도 있을 것이다.

로그인하지 않은 유저들 다루기

지금까지 위에서 다룬 내용은 로그인한 유저의 행동을 로그로부터 알아내는 방법이었다. 하지만 로그인하지 않은 많은 유저들의 방문은 어떻게 살펴볼 수 있을까? 웹 서버에서 세션 key를 발급하고는 있지만 발급된 key의 정보를 오랜 기간 유지해야 하며 사람이 아닌 봇에 대한 처리 또한 간단하지만은 않은 일이다. Google Analytics와 비슷한 기능을 하는 piwik을 사용해보려 했지만 필요한 기능에 비해서 유지 및 관리 비용이 부담스러운 수준이었다. 그래서 예전부터 이용하던 Google Analytics에서 전체 이용자 수와 신규 이용자 수를 가져오기로 했다.

실제 대시보드 만들기

지표를 살펴보기 쉽도록 대시보드의 형태로 funnel 정보를 나타내야 했다. 간단한 표와 그래프를 보여주기 위한 도구로는 jupyter notebook을 골랐고, pandasmatplotlib를 활용했다.

지금까지 위에서 만든 데이터를 읽어 DataFrame으로 만들고 각각의 이용자 수와 비율을 동시에 표로 나타냈다. 이는 공휴일이나 연말연시같은 이벤트에 이용자 수가 영향을 받기에 반드시 비율을 같이 볼 필요가 있다고 생각했기 때문이다. 그리고 그래프를 그릴 때 전체 이용자 수와 신규 이용자(대부분 비로그인 이용자들)를 같이 나타내면 로그인 이용자들의 수가 비로그인 이용자 수에 비해 매우 적어 로그인한 이용자들의 행동은 그래프에서 아주 작게 나타난다. 그렇기 때문에 로그인 이용자들의 행동만 따로 그래프로 그려야 눈으로 비율의 변화 정도를 확인할 수 있었다. 아래는 그렇게 그린 funnel 분석 그래프이다.

 

 

남은 과제들

대시보드의 표와 그래프로 funnel 지표는 살펴보았다. 하지만 다음 과정인 ‘각 단계의 행동을 행하거나 행하지 않은 이유’를 알아내는 것은 아직 수행하지 못했다. 이를 위해서는 로그를 더 자세히 여러 가지 방식으로 살펴봄으로써 funnel의 단계별 행동 이외에도 이용자가 어떤 방식으로 서비스를 이용하는지 알아내는 작업이 필요하다.

그리고 로그인하지 않은 이용자의 행동과 가입 후 한 행동을 연결해야 한다. 로그인 후의 행동을 분석해서 이용자 경험을 개선하는 것도 중요하지만 가입 이전에 무슨 행동을 하다 가입에 이르게 되었는지를 제대로 수집할 수 있다면 신규 이용자들을 가입시키는 과정 또한 개선이 가능할 것이기 때문이다.

덧1) 로켓펀치의 데이터 분석, 성장 전략 노하우가 담긴 책 ‘그로스 해킹 – 성장의 시대를 위한 안내서’가 출간 되었습니다.

덧2) 로켓펀치의 다음 데이터 분석 프로젝트는 ‘스타트업 연봉 분석’입니다.

글쓴이 : 정희동 (Software Engineer @로켓펀치) & 조민희 (CEO @로켓펀치)