— 데이터보다 중요한 건 ‘생성 당시의 상태’였다
서비스를 만들다 보면 한 번쯤은 추천 기능을 구현하게 된다.
관심사 기반 추천이든, 행동 기반 추천이든, 혹은 특정 데이터를 바탕으로 한 자동 추천이든 형태만 다를 뿐 구조는 비슷하다.
최근에 헬스케어 서비스에서 추천 기능을 설계하면서, 단순히 테이블을 만드는 문제라고 생각했다가 예상보다 깊은 고민을 하게 됐다. 결론부터 말하면, 이 문제의 핵심은 추천 로직이 아니라 사용자 입력 데이터와 그 입력이 발생한 시점의 상태를 어떻게 함께 저장할 것인가였다.
1. 처음에는 단순한 구조처럼 보였다
기능 요구사항은 직관적이었다.
- 사용자가 건강 카테고리를 직접 선택할 수 있음
- 건강검진 결과가 있으면, 수치 기반으로 자동 추천 카테고리가 생성됨
- 이후 영양성분 페이지에서 이 카테고리들을 기준으로 추천을 보여줌
그래서 테이블도 단순하게 생각했다.
- 사용자 선택 카테고리 저장
- 자동 추천 카테고리 저장
- 구분은 checkup_based_yn 같은 플래그로 처리
예를 들면:
- Y → 검진 기반 자동 추천
- N → 사용자 직접 선택
여기까지는 전형적인 CRUD 설계다. 크게 문제될 게 없어 보였다.
2. 그런데 UI 요구사항이 들어오면서 꼬이기 시작했다
UI에서는 단순히 카테고리 목록만 보여주는 게 아니라,
추천의 “근거”도 함께 노출해야 했다.
예를 들면:
- “건강검진 결과를 기반으로 추천해 드려요”
- “사용자가 선택한 관심사 기반 추천입니다”
여기서부터 질문이 생겼다.
이런 상황은 어떻게 구분하지?
케이스1
- 과거: 검진 데이터 없음
- 사용자가 카테고리 선택
- → 전부 사용자 선택 기반
케이스 2
- 나중에: 검진 데이터가 새로 들어옴
- 그런데 기존에 선택한 카테고리는 그대로 존재함
이 상태에서 서버는 이렇게 판단하게 된다:
검진 데이터 있음 → checkupResultYn = Y
하지만 실제로 카테고리는 “검진이 없을 때 사용자가 고른 것”이다.
UI 입장에서는:
- 검진 있음 → 검진 기반 추천으로 보이는데
- 실제로는 전혀 아님
이 순간부터 데이터의 “의미”가 틀어지기 시작한다.
케이스 3
또 놓쳤던 상황은 아래와 같은 상황이다.
- 검진 데이터는 있음
- 그런데 모든 수치가 정상
- → 자동 추천 카테고리 0개
이 경우 DB에는 이렇게 남는다:
- 전부 사용자 선택 카테고리만 존재
- checkup_based_yn = Y 인 row는 하나도 없음
그런데 실제 맥락은 이거다:
- 검진은 분명히 했음
- 단지 추천할 게 없었을 뿐
하지만 DB만 보면: “그냥 사용자가 선택한 카테고리만 있네?”
이렇게밖에 해석이 안 된다.
여기서 깨달았다.
지금 구분하려는 건 ‘카테고리 데이터’가 아니라 ‘추천이 만들어진 당시의 상태’라는 걸.
처음 만든 checkup_based_yn 플래그에 너무 많은 역할을 넣으려다 보니 이 결과에 도달하기 까지에도 꽤 시간이 걸렸다.
4. 문제의 본질은 데이터가 아니라 ‘시점’이었다
처음엔 이렇게 생각했다.
- 플래그를 하나 더 둘까?
- 검진 있었을 때 선택한 건지 표시해야 하나?
- 상태값을 추가해야 하나?
그런데 계속 고민하다 보니 근본 원인이 보였다.
지금까지는: “무슨 데이터를 저장했냐” 만 생각하고 있었다.
하지만 실제로 필요한 건: “그 데이터가 어떤 상태에서 생성됐냐” 였다.
정리하면 이거다:
우리가 저장한 것
| 사용자 선택 | 저장됨 |
| 자동 추천 결과 | 저장됨 |
| 검진 데이터 존재 여부 | 별도 테이블에 있음 |
하지만 빠진 게 하나 있었다. “이 추천이 만들어질 당시, 검진이 있었는가?” 이 정보가 없으니까, 계속 돌았던 것이다.
5. ‘없는 데이터’를 해석하려고 해서 더 꼬였다
특히 이런 상황에서 많이 헤맸다.
- 검진 있음
- 전부 정상
- 자동 추천 카테고리 없음
이건 사실 의미가 있는 상태다.
하지만 DB에는:
- 아무 row도 생성되지 않음
그런데 UI는 알고 싶어 한다. “검진을 기반으로 분석된 결과인가?”
즉,
- 데이터는 없지만
- 상태는 존재함
이걸 카테고리 row 존재 여부로 추론하려고 하니까 설계가 계속 꼬였던 거다.
6. 그래서 얻은 결론
추천 기능 설계에서 중요한 건
카테고리 테이블 구조 자체가 아니었다.
진짜 중요한 건 이거였다: 사용자 입력 데이터만 저장하면 충분한 줄 알았는데
실제로는 ‘입력 당시의 상태(context)’를 같이 저장해야 했다.
즉, 추천 시스템은 항상 두 가지를 함께 가진다.
1. 결과 데이터
- 어떤 카테고리가 추천됐는지
- 사용자가 무엇을 선택했는지
2. 생성 컨텍스트
- 검진이 있었는지
- 자동 추천이 동작한 상황인지
- 사용자 선택만 있었는지
이 두 개가 분리되지 않으면:
- UI 분기가 어려워지고
- 의미 해석이 꼬이고
- 나중에 정책 변경에도 취약해진다.
마무리
처음에는 단순히 “추천 카테고리를 어떻게 저장할까?”라는 데이터 구조의 문제처럼 보였지만, 실제로는 훨씬 더 본질적인 고민이었다. 결국 핵심은 하나의 값을 저장하는 것이 아니라, 그 값이 만들어진 순간의 상태(state), 그 변화를 만든 이벤트(event), 그리고 생성 당시의 맥락(context)을 함께 어떻게 모델링할 것인가에 있었다.
현재 추천 카테고리를 저장하는 테이블은 추천 컨텐츠나 추천 챌린지 뭐 이런 값들의 상태값을 저장할 수 있는 공통 테이블로 우선 설계는 해뒀다. 근데 이런 구조가 확장성이 있는지, 공통을 잘 쓰일 수 있는 구조인지는 조금 더 고민이 필요해보인다.
'Dev Log' 카테고리의 다른 글
| 파일 업로드: “썸네일/메인 이미지” 업로드에서 두 필드가 동기화되는 버그 트러블슈팅 (1) | 2026.02.22 |
|---|---|
| Java 컬렉션 프레임워크 정리: List, Set, Map, HashMap (0) | 2026.02.15 |
| 프론트엔드에서 처리하는가, 백엔드에서 처리하는가 (0) | 2026.02.01 |
| 두 대의 서버로 분산된 로그를 실시간으로 추적하는 방법 (0) | 2026.01.25 |
| 상태 분기 UI를 어떻게 테스트할 것인가: Test API를 만들기까지의 고민 (0) | 2026.01.18 |