Q4-1
토스 가이드에 "기차표를 제외하고 출발역/도착역/여행 방식/인원수는 유지되어야 해요"라는 요구가 있었는데요, 어떻게 풀었나요?
핵심 포인트
- PDF에 명시된 요구사항 — 즉, 평가 대상이라는 시그널.
- 검색 조건과 선택한 티켓의 수명을 다르게 가져가야 풀리는 문제.
- 그래서 atom 파일을 두 개로 분리했습니다 —
searchConditionAtom(역/날짜/여행방식/인원수)과ticketConditionAtom(가는편/오는편 티켓). - "다시 선택하기" 버튼은 티켓 atom만 초기화하고 검색 조건 atom은 손대지 않습니다.
- atom이 모듈 스코프에 살아 있으므로, navigate로 SearchPage로 돌아가도 검색 조건은 그대로 남아 있습니다.
모범 답안먼저 답해보고 펼치기
이 부분이 토스 가이드에 명시적으로 적힌 요구사항이라 가장 신경 쓴 지점이었습니다.
해결의 핵심은 수명이 다른 두 종류의 상태를 분리하는 것이었어요. 검색 조건 — 역, 날짜, 여행 방식, 인원수 — 은 사용자가 다시 선택하기를 눌러도 그대로 남아야 하고, 선택한 티켓 — 가는편/오는편 — 은 새로 골라야 하니 초기화돼야 합니다. 그래서 atom 파일을 의도적으로 두 개로 나눴습니다. atoms/searchConditionAtom.ts에는 6개 검색 조건 primitive atom을 두고, atoms/ticketConditionAtom.ts에는 departureTicketAtom/arrivalTicketAtom + resetSelectedTicketsAtom만 따로 분리했습니다.
이렇게 분리하니까 ConfirmPage의 "다시 선택하기" CTA는 한 줄로 끝나요. ConfirmBottomCTA.tsx의 handleReselect를 보면 resetSelectedTickets()를 호출한 뒤 navigate(SEARCH, { replace: true })로 끝납니다. 검색 조건 atom은 손도 대지 않아요. atom이 모듈 스코프에 그대로 살아 있기 때문에 SearchPage로 돌아가면 자연스럽게 직전에 입력한 역·날짜·인원수가 화면에 다시 그려집니다. 별도의 sessionStorage나 라우터 state 전달 같은 장치가 필요 없었던 게 atom 분리 덕이었습니다.
또 하나 중요한 건 — 이 분리가 단순히 "다시 선택" 시나리오만을 위한 게 아니라, 도메인적으로도 의미가 맞다는 점이에요. 검색 조건은 사용자가 직접 채우는 입력값이고, 티켓은 그 입력값으로 조회한 결과 중 사용자가 선택한 값입니다. 책임이 다른 상태들이라 분리하는 게 자연스러웠고, 결과적으로 다시 선택 시나리오가 자동으로 풀린 거죠.
이 답변, 어땠나요?
꼬리 질문
-
Q4-1-a. 만약 atom 한 파일에 다 몰아넣고
resetAllAtom만 만들었다면 어떻게 됐을까요? → "다시 선택하기"가 검색 조건까지 다 날려버려서 PDF 요구사항을 위반합니다. 결국 partial reset 함수를 또 만들어야 하는데, 그러면 reset 책임이 한 atom에 모이고 변경할 때마다 빠뜨릴 위험이 생깁니다. 파일을 나누면 reset 단위가 자연스럽게 정해지죠. -
Q4-1-b. 그럼 둘을 한 파일에 두되 reset 함수만 두 개 두는 건 어땠을까요? → 가능하지만 도메인 경계가 흐려집니다. 검색 조건은 SearchPage가 주로 쓰고, 티켓은 TicketsPage 이후가 씁니다. 라이프사이클과 사용처가 다른 상태를 한 파일에 두면 import 그래프와 의존성도 섞여서, 나중에 누가 봐도 어디서 reset돼야 하는지 헷갈릴 거 같았습니다.
-
Q4-1-c. SearchPage로 navigate할 때
replace: true를 주신 이유는요? → 히스토리 스택을 깔끔하게 유지하기 위해서입니다. ConfirmPage에서 뒤로가기가 다시 ConfirmPage로 돌아가지 않도록 하려는 의도예요. 그렇게 하지 않으면 사용자 입장에서 뒤로가기 버튼의 행동이 헷갈립니다.
CS · 이론
- 상태의 수명(lifetime) 관점에서의 모듈 분리: 한 객체에 들어가야 할지 분리해야 할지를 결정할 때 "같이 만들어지고 같이 죽는가"를 묻는 게 좋은 휴리스틱입니다. 검색 조건과 선택 티켓은 라이프사이클이 다르므로 분리가 정답이었습니다.
- Single Source of Truth & 부분 초기화(Partial Reset): SoT를 지키되, reset 단위를 도메인 경계와 일치시키면 reset 함수가 단순해지고 누락 위험이 줄어듭니다.
- Module-scope state: jotai의 atom은 import 시점에 모듈 스코프에 생성되어 페이지 이동에도 살아남습니다. 단점은 새로고침 시 날아간다는 것 — 이건 Q4-4에서 다룹니다.