스터디에 직접 참여하면서 계속 들어온 이야기였다. 사람들은 한 지역만 원하지 않는다. 집 근처도 되고 학교 근처도 되는데 신청할 때는 한 곳만 고를 수 있었고, 고르지 않은 쪽에서 열리는 스터디에는 후보로도 잡히지 않았다.
한 멤버가 스터디 크루를 한 번에 네 개 가입한 것을 봤다. 확인해 보니 크루를 중복해서 가입한 멤버가 적지 않았다. 제약을 사용자가 스스로 우회한 흔적이다.
여러 위치를 고르는 건 예전에 되던 기능이다. 매칭 알고리즘을 바꾸면서 한 곳으로 줄었고, 그 뒤로 미뤄둔 과제였다.
반경을 넓히는 건 답이 아니다
가장 쉬운 답은 반경을 키우는 것이다. 그런데 원은 중심에서 같은 거리에 있는 점들의 집합이라, 떨어진 두 지점을 함께 담으려면 그 사이 전부를 함께 담게 된다. 집과 학교가 6km 떨어져 있으면 그 사이의 관심 없는 동네까지 전부 후보가 된다. 두 곳이 되게 하려다 여덟 곳이 되는 셈이다.
그래서 반경 대신 기준점을 늘렸다. 최대 두 개, 반경은 공통. 둘 중 어느 하나라도 범위에 들면 참여 가능으로 본다.
매칭에 어떻게 반영했나
매칭은 장소 중심으로 돈다. 등록된 스터디 장소마다 갈 수 있는 사람을 모아 그룹을 만든다. 그래서 거리 판정이 전부 같은 모양이다.
haversineDistance(장소, 참여자) <= 참여자의 반경기준점을 늘리는 일은 그 자리를 “기준점 중 가장 가까운 것까지의 거리”로 바꾸는 게 전부였다.
설계에서 중요했던 건 참여자 한 명당 내부 항목을 하나로 유지한 것이다. 기준점이 두 개라고 항목을 두 개로 늘리면 한 사람이 두 번 세어진다. 두 명이 점 네 개를 만들어 “3명 이상 모이면 확정”을 통과하고, 실제로는 두 명인 스터디가 열린다. 항목은 그대로 두고 거리 계산만 최소값으로 바꿨다.
같은 사람의 기준점이 500m 안에 붙어 있으면 하나로 병합한다. 강남역과 역삼역을 따로 찍어도 범위가 넓어지지는 않는다.
슬라이더 단계별로 실제 반경은 이렇게 걸린다.
| 슬라이더 | 반경 | 인원이 모자랄 때 |
|---|---|---|
| 1단계 | 2.1 km | 3.15 km |
| 2단계 | 3.1 km | 4.65 km |
| 3단계 | 4.1 km | 6.15 km |
고르는 화면을 지역 단위로 바꿨다
기준 위치를 정하는 방법이 장소 검색뿐이었다. 집 근처야 바로 나오지만 두 번째 위치는 검색어부터 떠올려야 한다.
지역 버튼을 위에 두고 검색을 아래로 내렸다. 지역을 고르면 그 지역의 기본 스터디 장소가 기준 위치가 된다. 스터디 크루 딥링크가 쓰던 것과 같은 데이터라 새로 만들 것이 없었다. 여덟 개 지역을 가나다순 2열로 놓아 가로 스크롤 없이 한 번에 보이게 했다.
지도는 기준점이 둘일 때 두 지점이 모두 보이도록 맞춘다. 맞추는 기준은 두 점이 아니라 각 원의 경계다. 보여야 하는 건 점이 아니라 원 전체이기 때문이다.
참여자 카드의 지역 배지도 두 개까지 표시한다. “광진구 외 1곳”으로 줄이면 두 번째가 어딘지 알 수 없고, 그러면 누가 어디서 오는지 가늠한다는 이 배지의 쓸모가 사라진다.
신청한 날짜가 화면에 그대로 남게 했다
서버는 제출된 날짜 목록을 이번 주 최종 상태로 해석한다. 목록에 없는 날짜는 신청이 지워진다.
화면은 다르게 잡혀 있었다. 이미 신청한 날짜는 확정된 것으로 보고 다른 색으로 표시하고 선택 대상에서 뺐다. 신청을 한 번에 끝낸다고 보면 자연스러운 설계다. 그런데 기준점이 늘면서 신청을 여러 번 나눠 하는 흐름이 생기자 화면이 가리키는 것과 서버가 저장하는 것이 어긋났다. 이 상태로 날짜를 하나 더 신청하면 앞서 신청한 날짜가 목록에서 빠진 채 제출된다.
그래서 이미 신청한 날짜를 처음부터 선택된 상태로 뒀다. 선택 목록이 곧 최종 상태가 되고, 해제하면 그 날짜가 취소된다. 별도 색과 비활성 분기가 없어져 화면 상태도 셋에서 둘로 줄었다.
이 구조는 기존 신청이 화면에 도착한 뒤에 초기 선택이 일어나야 성립한다. 아직 로드되지 않은 상태와 신청이 없는 상태를 구분하고, 로드 전에는 제출을 막았다.
참여 시간을 실제로 반영하게 했다
참여 시간은 그룹을 채우는 단계에서만 보고 있었다. 처음 서너 명을 묶는 단계에서는 거리만 봤다. 기준점이 하나일 때는 같은 동네 사람끼리 묶이니 시간대도 대체로 붙어 있었는데, 후보 범위가 넓어지면 그 전제가 약해진다.
그래서 시간 검사를 형성 단계에도 적용했다. 여기에 시드 재시도를 붙였다. 후보를 앞에서부터 쌓는 방식이라, 소수파 시간대가 먼저 잡히면 뒤따르는 후보가 전부 거부되어 그룹이 아예 안 만들어진다. 최소 인원을 못 채우면 다음 후보를 시작점으로 잡고 다시 시도한다.
| 후보 구성 | 시드 재시도 없음 | 있음 |
|---|---|---|
| 14–18시 2명 + 18–22시 4명 | 그룹 없음 | 저녁 4명으로 성립 |
여러 장소에 갈 수 있는 사람이 앞 장소에 먼저 흡수되어 뒤 장소가 못 열리는 경우도 우려했다. 그래서 미달 장소를 살리는 보정 패스를 만들었는데, 검증해 보니 기존 정렬이 이미 그 상황을 처리하고 있었다. 후보를 “갈 수 있는 곳이 적은 사람” 순으로 세우기 때문에 여러 곳이 가능한 사람은 자연히 뒤로 남는다. 세 경우 모두 결과가 같아 지웠다.
남은 것
지하철과 경로는 다루지 않았다. “2호선이면 어디든 간다”는 기준점 두 개로도 표현되지 않는다. 역을 기준점으로 찍는 것으로 일부만 대신하고 있다.
참여 시간 프리셋이 경계에서 맞닿아 있다. 점심 14–18시와 저녁 18–22시는 겹치는 구간이 0분이라, 시간 검사를 넣은 뒤로 두 프리셋을 고른 사람은 같은 그룹이 되지 않는다. 의도한 결과인지는 더 봐야 한다.
매칭 성사 수가 어떻게 변하는지도 아직 확인하지 않았다. 제약을 추가했으니 줄어드는 게 정상이지만 얼마나 줄어드는지는 며칠 지켜봐야 안다.
기존 신청은 기준점 정보 없이 저장돼 있어도 서버가 좌표 한 점으로 정규화한다. 마이그레이션 없이 배포했다.
크루를 네 개 가입하던 멤버에게는 이제 그럴 이유가 하나 줄었다. 그 방식이 실제로 줄어드는지는 다음에 확인할 일이다.