Feed Infra팀을 소개해요!

김동현
당근 테크 블로그
14 min readNov 14, 2023

안녕하세요. 당근 Feed Infra팀의 소프트웨어 엔지니어로 일하고 있는 Fred예요. 피드 서비스의 과거와 현재, 그리고 지금 어떤 시도들과 고민들을 하고 있는지 말씀드리려고 해요.

초기의 당근은 중고거래 서비스를 기반으로 성장해 온 서비스이지만 동네의 연결이라는 큰 목표를 가지고 있었어요. 중고거래앱이 아니라 동네에서 일어나는 모든 비즈니스를 연결하는 O2O 서비스가 목표였죠. 하지만 피드에 노출하게 될 콘텐츠들의 유형이 예측 불가능 하다고 생각하여 보편적인 SNS 서비스의 피드 설계 구조를 가져가기에는 새롭게 만들어지는 콘텐츠를 빠르게 피드에 노출하는 것은 어려움이 있을 것이라고 판단했어요.

위와 같은 이유로 피드 서비스에서는 2가지에 집중했는데요.

  1. 사내의 새로운 서비스들의 콘텐츠들을 피드에 쉽게 노출할 수 있을 것. (Backend)
  2. 앱 업데이트가 없더라도 콘텐츠가 노출될 수 있을 것(Frontend)

각 포지션에서 했던 고민들을 풀어보려고 해요.

Phase 1. Just Push It!

보통 SNS 서비스들에서는 콘텐츠가 작성되는 곳이 한 곳이고 대체적으로 미디어를 올리거나 글을 쓰는 경우가 많은데요. 당근은 중고거래를 시작으로 중고차, 당근알바 등 서로 다른 회사라고 칭할 수 있을 만큼 사내에 발행되는 콘텐츠들의 다양성이 매우 크고 각 서비스별로 콘텐츠 서빙 전략이 다르다고 생각했어요. 그래서 보편적인 피드 모델인 Fan-in이나 Fan-out을 고려하기가 애매했어요. 하나의 큰 저장소에 콘텐츠들을 담았을 때 서비스별로 원하는 정렬의 방법, 조회의 빈도등 예측할 수 없었고 초기에는 혼자서 피드 서비스를 만들고 운영해 나가야 했기에 어떻게 하면 PMF를 찾아나가는 다양한 서비스들의 콘텐츠들이 피드에 노출되고 개인화하는 것에 빠르게 지원할 수 있을까 고민했어요. 그러다 피드 서비스가 모든 것을 모은 후 노출 하는 것이 아니라 각 서비스들이 피드에 노출할 수 있는 규약을 만들고 전달한 콘텐츠를 정하는 권한을 위임해야겠다고 생각했어요. 어떤 서비스가, 어떤 콘텐츠가 생겨날지 예측할 수도 없었기에 개인화를 위한 시스템을 만드는 것이 오히려 더 큰 기술 부채가 될 것이라고 생각했었거든요. 그래서 각 서비스에서 1차적으로 정렬한 콘텐츠들을 어떤 순서와 우선순위로 노출할지 정하는 역할을 피드 서비스가 가져갔어요.

그래서 첫 피드 시스템은 다음과 같은 디자인으로 만들어졌어요.

고객이 피드를 요청하면 피드 서비스는 피드에 노출할 콘텐츠를 가지고 있는 서비스들에게 요청하여 콘텐츠를 수급받아요. 피드 서비스에 정의되어있는 규칙에 의해서 중고차, 당근알바 등 콘텐츠를 노출할 수 있게 해 주었어요. 사용자들은 당근의 홈피드를 당근의 다양한 콘텐츠가 보이는 피드가 아닌 중고거래피드로 인식하고 있어요. 그래서 새롭게 선보이는 우리들의 콘텐츠를 하나의 광고라고 보고 중고거래 외의 콘텐츠가 노출될 수 있는 위치를 조정하고 같은 위치를 경쟁하는 서비스들 간의 우선순위를 조정하는 장치를 피드 서비스에서 제공했어요.

HTTP로는 다음과 같은 형태의 응답 구조를 가진다면 누구나 피드에 노출할 수 있었어요. 이후 GRPC가 도입되고 grpc로 통신할 때도 아래와 같은 구조를 응답객체로 가지고 있는 것을 권장했어요.

{
"data": [
{
"index": "int", // 노출 할 위치
"resource": {
"id": "int", // integer id
"sid": "string", // string id
"model": "string", // entity type
"score": "float64", // 콘텐츠의 rank 값
"serialized": "stringified viewtype" // 아래에서 소개될 viewtype 데이터
}
}
]
"meta": {
}
}

콘텐츠 서빙과 개인화를 일단은 각 서비스에 위임하고 콘텐츠를 빠르게 노출할 수 있는 방향으로 설계했어요. 앱에서도 별도의 업데이트 없이 빠르게 노출하기 위해 Viewtype이라는 것도 만들었답니다.

Viewtype

피드 서비스를 만들 당시의 당근은 30~60의 사용자 비중이 매우 높았고 구형의 안드로이드 사용자도 많았기에 업데이트 속도가 빠르지 않았는데요. 그로 인해서 새로운 기능을 사용자에게 도달시키기까지 시간을 단축하기 위해서 Viewtype이라는 아이디어를 냈어요. 이 아이디어의 출발은 우리가 새로운 앱을 만들 때는 웹뷰로 만들고 있으니 별도의 업데이트를 하지 않더라도 피드 아이템을 그릴 때 필요로 하는 정보만 골라서 보내주면 별도의 업데이트를 하지 않아도 되지 않을까? 하는 것에서 출발했어요. 당근 피드에는 다양한 뷰타입이 존재하는데 그중 하나의 Viewtype을 보여드릴게요.

다음과 같은 형태로 client에게 응답을 하게 되면 위와 같은 형태로 홈피드에 노출되게 됩니다! 아이템을 클릭하면 웹뷰로 이동했기 때문에 업데이트를 하지 않더라도 피드에 노출될 수 있었어요. 물론 빠르게 View를 그리는 것에는 효과적이었으나 관심 숫자가 올라가거나 채팅 숫자가 올라가는 상태 변화나 네이티브에서 콘텐츠와 interaction을 갖는 것에 대한 어려움이 있는 상태입니다.

그래도 피드에서 빠르게 노출할 수 있는 길이 열렸고 이를 기반으로 당근의 O2O서비스 초기 성장에 기여할 수 있었어요.

e.g. 당근알바

당근알바는 우리 동네의 구인구직 플랫폼인데요. 초창기에 제품을 만들고 유입을 만드는 과정에서 피드를 사용하였고 피드에 컨텐츠를 노출하면서 공고수는 100% 성장, 전체적인 서비스 지표의 50%의 성장을 만들어냈어요.

Phase 2. Assemble!

이러한 전략으로 초기에는 피드에 노출되는 것 그 자체는 빠르게 적용될 수 있었으나 개인화의 단계로 넘어가야할 만큼 콘텐츠가 쌓였을 때 각 서비스들의 데이터만을 가지고 각자 개인화 하도록 하는 전략은 더 이상 큰 임팩트를 만들어내지 못하고 있었어요. 사용자들이 제공하는 데이터들을 모든 서비스들이 조화롭게 사용할 수 있는 상태도 아니었고요. 그래서 사내의 모든 콘텐츠를 모아서 전체 최적화를 하기로 결정하였습니다. 이를 잘하기 위해 피드라는 제품을 잘 만들기 위한 조직 구조 변경을 했는데요. 피드품질팀 + 피드 ML 인프라 + Feed Infra를 합쳐 24명이 있는 실을 만들었어요. Feed Infra팀은 10명인 팀이 되었고요. (이 글을 보시는 분이 계시다면 저희와 함께해 주세요. 👉 공고 바로가기. 하고 싶은 것들이 너무 많습니다.)

피드라는 제품에서 당근 내에서 사용자들이 만들어주시는 많은 이벤트와 모든 콘텐츠들을 어떻게 하면 잘 활용할 수 있을지 고민하고 개발하고 적용하는 과정에 있습니다.

Backend

Feed Infra팀은 3가지 새로운 컴포넌트를 만들고 있어요.

  1. Feed에 노출되기 전에 적용되어어야 하는 정책을 담당하고 콘텐츠의 조합을 담당하는 Feed Mixer
  2. 당근의 콘텐츠 제공자들의 모든 콘텐츠를 저장하는 Feed Entity Service
  3. 콘텐츠에서 발생하는 다양한 명시적 피드백을 저장하기 위한 Feedback Service

Feed Mixer

클라이언트의 요청을 받아 추천 모델을 통해 개인화된 콘텐츠와 아직 개인화를 하기에는 충분히 성장하지 않는 서비스들의 콘텐츠들을 섞고 피드 정책에 따른 페널티를 적용하는 서비스예요.

Feed Entity Service

피드에서 안정적인 서빙과 다양한 실험을 위한 인프라를 구축하기 위해서 피드에 노출될 수 있는 모든 엔터티를 수집하고 서빙하는 서비스예요. 사내의 다양한 콘텐츠를 한데 모아서 통합 추천 모델을 만들기 위한 준비작업에 박차를 가하고 있어요.

Implicit Feedback Service

당근의 콘텐츠에서 발생할 수 있는 관심, 좋아요, 댓글, 채팅, 신고, 차단, 안 보기 등등 콘텐츠에서 발생하는 명시적 피드백을 저장하는 서비스예요.

Frontend

백앤드 외에도 화면 내에서 다양한 콘텐츠를 다양한 UI로 다룰 수 있도록 기존의 Viewtype을 개선하고자 했어요.

콘텐츠를 한 곳에 모아 놓았고 콘텐츠 특성에 맞는 모양을 만들 수 있으면 퍼포먼스를 극대화할 수 있을 것이라고 생각했어요. 이에 Feed Infra팀에서는 기존의 Viewtype을 넘어서 SDUI를 새로 만들기로 했습니다.

이를 ViewTemplate이라고 명명했고 Text, Image, Button 등 사용할 수 있는 컴포넌트를 적용하고 스타일을 자유롭게 적용할 수 있도록 했어요.

ViewTemplate이라는 아이디어를 시작할 당시에는 팀은 백엔드 엔지니어만으로 구성된 팀이었기에 이 아이디어가 실제로 동작할 수 있을 것인지 검증하기 위해 웹으로 먼저 검증을 진행했어요.

가능하다고 판단된 후, 관심피드를 ViewTemplate으로 구현하여 유저들에게 실험으로 내보냈는데요. UI에 대한 오류 제보가 없는 것을 보고 가능성을 보았어요. 이후로 계속 진행될 수 있었으면 좋았을 텐데 클라이언트 리소스 부족과 Mixer, Entity Service 등 좀 더 시급한 문제가 있어서 이 이상의 진행은 보류해 둔 상태예요.

피드 인프라에 합류하셔서 같이 만들어나가요! 👉 공고 바로가기.

🕵️ 이거 될 것 같지 않아요?

피드실에서는 누구나 아이디어를 낼 수 있고 그것을 데이터로 검증하고 설득하는 과정을 경험해 볼 수 있어요. 이미 실험의 중요성은 많이 알려져 있는데요. 특히 저는 A/B Testing을 통해 우리가 원하는 미래를 선택하는 것 같아서 굉장히 매력적인 작업이라고 생각해요. 실험을 많이 하기 위해서는 실험을 하기 위한 준비작업이나 장애물이 최대한 적어야 하기에 피드실에서는 이를 위해 빠르고 확장 가능한 인프라도 구축하고 있어요.

또한, 실험을 통해서 나온 데이터를 기반으로 의사결정을 하기에 감 보다는 객관적인 지표를 바탕으로 논의하고 있어요. 단기간에는 효과가 있지만 장기적으로 해를 끼칠 수 있는 아이디어도 있고 단기적으로는 변화가 없지만 우리가 주고자 하는 가치를 위해 가야하는 방향이라는 모두의 동의가 있다면 숫자보다 우선시 될 수 있어요. 물론 얼마나 나빠지는 인지한 상태에서 하는 선택이기에 기회비용을 계산하며 움직여요.

🧑‍💻 이렇게 일하고 있어요!

PRD, Tech Spec

피드실은 PRD를 작성하여 Key Concept에 대해서 논의를 하고 Tech Spec을 통해 세부 구현 사항을 미리 논의해요.

PRD와 Tech Spec이 무엇인지 궁금하시다면 아래 링크를 참고해주세요!

PRD: https://en.wikipedia.org/wiki/Product_requirements_document
Tech Spec: https://blog.banksalad.com/tech/we-work-by-tech-spec/

작업이 들어가기 전에 함께 하는 동료들이 같은 이해를 가지고 한 몸처럼 일할 수 있도록 해요. 특히 Tech Spec에서는 가능한 모든 인터페이스를 논의하고 문서를 읽었을 때 모두가 같은 결과를 도출할 수 있도록 몇 번이고 치열하게 논의합니다. 가끔은 코드를 작성하지 않는 날이 길어져서 코드가 그리울 때도 있어요.

중간에 정보가 부족했거나 예상하지 못한 다른 일들이 생길 때도 있지만 이미 논의가 끝났기 때문에 작업은 제법 일사천리예요. Tech Spec과 친해지는 시간을 가지다가 처음으로 제대로 사용하게 된 프로젝트는 문서 작성에 2주를 소요했지만 이를 코드로 옮기는 작업은 1주에 불과했어요. 뚫린 아우토반을 달리는 느낌이었습니다. 우리 모두의 회고는 “생각은 끝났고 달리기만 했다”였습니다. 피드실에서 이런 경험을 해보시는 건 어때요? 👉 공고 바로가기

💫 이렇게 놀기도 해요

당근에는 매주 마지막 주 수요일에 문화의 날이라는 시간이 있어요! 아침에는 사내문화, 팀 문화에 대한 회의를 해서 우리의 문화를 다듬는 시간을 가지고 오후에는 액티비티를 즐겨요. 팀 또는 실 단위로 구성되는 달과 주제에 익명의 사람들이 모여서 하루 전에 참여 명단이 공개되는 달이 있어요.

지난 문화의 날에는 피드실 구성원 중 해산물을 좋아하는 사람들끼리 모여서 저렴해진 킹크랩을 먹으러 가락시장에 갔어요.

워크샵 & 플레이샵

반기에 한 번씩 팀원들끼리 피드의 방향성에 대해서 이야기를 나누고 어떻게 할지 전략을 세우는 워크샵을 가기도 하고 돈독한 관계를 위해서 플레이샵을 떠나기도 해요.

🌟 동료를 소개해요!

Evan

Q. 안녕하세요! 반갑습니다.

A. 안녕하세요, 당근 Search & Discovery 부문에서 피드실에서 소프트웨어 엔지니어로 일하고 있는 Evan입니다.

Q. 입사하실 때는 같은 서비스코어 부문 다른 팀이었지만 대대적인 조직변경을 하면서 피드 인프라팀으로 오시게 되었을 때 피드 인프라팀의 첫인상은 어떠셨어요?

A. 조직변경을 했지만 같은 부문이었고 옆자리였기에 거리감은 없었어요. 기존에 하고 있는 업무 또한 플랫폼 관련 업무라는 점에는 처음에는 크게 다른 점이 없었던 것 같고요. 하지만 이후에 피드 인프라팀에서 피드라는 제품을 만들기 위한 모든 직군이 하나의 목적조직인 피드실이 되면서 확실히 달라졌어요.

Q. 어떤 지점이 달라졌나요? 기억에 남는 것이 있으신가요?

A. 플랫폼으로써 어떻게 안정적으로 전달할지를 고민하는 것에서 사용자의 경험, 피드백을 잘 받을 수 있는 환경, 개인화를 위한 Feature 등 피드라는 하나의 제품을 고민하는 팀이 되어가는 과정이 재밌었어요. 특히 동네생활 피드 개인화 프로젝트를 진행하면서 기존보다도 더 많은 지점에서 사용자를 생각할 수 있게 되고 아이디어들을 제품에 빠르게 실험해 볼 수 있어서 좋았습니다.

Q. 이 글을 보고 계신 미래의 동료에게 한마디 남겨주세요!

A. 당근의 피드를 통해 우리 동네에서 할 수 있는 모든 것들을 보여주기 위해 노력하고 있어요. 동네의 연결을 만들어보고 싶은 분이라면 피드 인프라팀에 합류해보세요!

Carter

Q. 안녕하세요! 반갑습니다.

A. 안녕하세요, 당근 Search & Discovery 부문에서 피드실에서 소프트웨어 엔지니어로 일하고 있는 Carter입니다.

Q. 2년 전에 인턴으로 들어오셔서 정규직으로 전환되셨어요! 인턴 하는 과정에서 어려움은 없으셨나요?

A. 제가 입사할 당시에는 200명 정도 되는 스타트업(?) 이였어요. 그때 당시에는 플랫폼 부문의 인턴이었고 Golang을 사용하는 조직이었는데요. 인턴과정 초기에는 부문의 인턴들과 기존의 팀원 분들과 함께 Golang을 파트별로 공부해서 Golang을 서로에게 알려주고 공부하는 시간을 가졌어요. 인턴 계약은 3개월이었는데 1개월이 지났을 때 제가 속해있던 피드 인프라팀에서 “Bigquery에 있는 데이터를 일정한 주기로 가공하여 데이터베이스에 저장하여 조회하는 서비스”를 맡겨주셨어요. 처음에는 어떻게 설계할지 일주일을 고민했고 이게 인턴 시절 기억에 남는 어려움이었던 것 같아요. 고민하다가 버디(온보딩을 도와주는 동료)에게 물어보면서 해결되는 경험을 하고나서는 혼자 끙끙 앓지 말자는 생각을 다시 한번 하게 되었어요.

Q. 평가받는다고 생각해서 중압감 때문에 그랬을 것 같아요. 인턴 과정이 끝난 후에 기억에 남는 재밌는 일이 있나요?

A. 피드에서 발생하는 콘텐츠들의 CTR, CVR 지표를 보기 위한 피드 성능 대시보드라는 사내 제품을 만들었을 때 재밌었어요. 위에 언급되었던 프로젝트를 여기에서 사용하게 되기도 했고요. 그 외에도 글에서 소개된 View Template를 만들 때 React를 하면서도 재밌었는데요. 처음으로 React를 가지고 제품을 만들다 보니 예상하지 못했던 사이드 이펙트들이 많았어요. 사내의 프론트엔드 엔지니어분들이 모여있는 슬랙 채널에서 도움을 요청하니 다들 관심 가져주시고 적극적으로 도움을 주셔서 잘 해결할 수 있었어요. 서로의 프로젝트에 관심을 가질 수 있는 투명성과 문화도 새삼 다시 한번 느껴졌어요.

Q. 이 글을 보고 계신 미래의 동료에게 한마디 남겨주세요!

A. 당근에서 좋은 엔지니어링 문화, 팀 문화를 경험하며 함께 압축성장 하실 분을 찾고 있어요!

🚀 피드 인프라팀 채용 중!

--

--