잡담··5 min read

개발자의 점심 메뉴 결정 알고리즘

매일 반복되는 점심 메뉴 고민을 코드로 해결해보려 한 삽질기

오늘 뭐 먹지

매일 11시 40분이면 팀 슬랙에 같은 질문이 올라온다. "점심 뭐 먹을까요?" 그리고 아무도 대답 안 한다. 5분 정도 침묵이 흐르다가 누군가 "아무거나요"라고 치면, 또 5분 침묵. 이 과정이 매일 반복된다.

사실 "아무거나"가 제일 어려운 주문이라는 걸 우리 모두 알고 있다. (근데 매일 "아무거나"를 외친다.)

그래서 진짜 알고리즘을 짜봤다

어느 날 점심시간에 농담 반 진담 반으로 랜덤 점심 메뉴 추천기를 만들었다. 처음에는 단순 랜덤이었다. 회사 주변 식당 23개를 배열에 넣고 Math.random()으로 돌리는 거.

const restaurants = ['김밥천국', '중국집', '돈까스', ...];
const pick = restaurants[Math.floor(Math.random() * restaurants.length)];

1주일 써봤는데 문제가 생겼다. 월요일에 중국집 나오고, 화요일에 또 중국집 나오고, 수요일에 또 중국집. 랜덤이란 게 원래 그렇다. 사람은 랜덤이 "골고루 나오는 것"이라고 착각하는데, 진짜 랜덤은 편향이 있다.

가중치를 넣어봤다

그래서 최근에 간 식당은 가중치를 낮추는 로직을 추가했다. 3일 이내에 간 곳은 확률 0, 일주일 이내는 확률 50% 감소. 꽤 합리적이라고 생각했다.

근데 여기서 또 다른 문제. 팀원 6명의 취향이 다 다르다. 한 명은 매운 거 못 먹고, 한 명은 일본식만 좋아하고, 한 명은 가격에 민감하다. (1만 원 넘으면 "비싸다"를 시전한다.)

결국 각 팀원의 선호도를 가중치로 넣기 시작했다. 여기서부터 뭔가 이상해지기 시작했다. 점심 메뉴 추천기가 슬슬 추천 시스템이 되어가고 있었다.

여기서부터 꼬이기 시작했다

팀원 선호도 데이터를 모으려고 구글 폼을 만들었다. 23개 식당에 대해 1~5점으로 평가해달라고 했다. 6명 중 4명이 응답했다. 나머지 2명은 "아무거나"라고 했다. (그 "아무거나"가 문제라니까.)

데이터를 모아서 협업 필터링 비슷한 걸 적용해봤다. 근데 6명 데이터로 협업 필터링을 하면 의미가 없다는 걸 3시간 만에 깨달았다. 표본이 너무 작다.

결국 단순 평균 점수에 최근 방문 패널티만 적용하는 걸로 돌아갔다. 3시간 날린 거다.

실제로 쓰이고 있나

놀랍게도 2개월째 쓰고 있다. 슬랙 봇으로 만들어서 /lunch라고 치면 추천이 나온다. 팀에서 제일 인기 있는 기능은 "거부권"이다. 추천 결과가 마음에 안 들면 /lunch veto를 치면 다시 돌린다.

근데 통계를 보니까 평균 2.3번 거부권을 행사한다. 결국 3번째쯤에 "그냥 이거 가자"가 된다. 알고리즘이 메뉴를 정해주는 게 아니라, 거부할 수 있는 선택지를 주는 거였다.

교훈 같은 건 없다

사실 이 프로젝트에서 기술적으로 배운 건 별로 없다. 6명 데이터로 추천 시스템을 만들겠다는 발상 자체가 오버엔지니어링이었다는 것 정도. (사실 그냥 만들어보고 싶었을 뿐이다.)

근데 이상하게 이 봇이 팀 분위기에는 도움이 됐다. 점심 메뉴 때문에 어색한 침묵이 사라졌고, 봇 결과를 보면서 "아 이거 어제 갔잖아 ㅋㅋ" 하는 대화가 생긴다.

아무튼 내일도 11시 40분에 /lunch를 칠 거다. 그리고 아마 거부권도 쓸 거다.

관련 글