- 발행일
BFF라고 적어 두고 msw를 지운 홈 화면 — 커밋 제목에 있던 두 단어가 코드에는 없었다
BFF라고 적어 두고 msw를 지운 홈 화면
이 글은 2026년 9월에 당시 커밋 이력을 다시 보며 정리한 것입니다. 날짜는 작업한 날 기준입니다.
TripTune 홈 화면에는 인기 여행지와 추천 테마 여행지 슬라이더가 있습니다. 2025년 3월까지는 광화문·성산일출봉·에펠탑·타워브릿지 사진을 컴포넌트 안에 박아 두고 돌리는 화면이었어요. 백엔드가 여행지 API를 열면서 이걸 실제 데이터로 바꿨습니다. 커밋은 셋입니다.
03-13 14:26 홈화면 추가 구축 시작 : API 설계 (for BFF) c6724a4
03-17 17:53 메인 페이지 msw 제거 b897f13
03-17 22:36 버튼 바 이슈 수정 : swiper 충돌 ae5f33e
제목만 보면 BFF 계층을 설계하고 msw 목업을 걷어낸 것처럼 읽힙니다. 코드는 그렇지 않았어요.
3월 13일 — 사진 배열을 데이터 배열로
c6724a4는 HomePageBestTravel.tsx(162줄)를 지우고 HomePagePopularTravel.tsx(242줄)를 새로 만듭니다. 새 파일에도 배열이 있습니다.
const HomePagePopularTravel = () => {
const images: TravelItem[] = [
{
placeId: 162,
address: '서울특별시 중구 동호로31길 21',
detailAddress: '(충무로5가)',
placeName: '묵정어린이공원',
thumbnailUrl: null,
},
// ... 5건
];
const [travelList, setTravelList] = useState<TravelItem[]>(images);
에펠탑 대신 실제 API 응답을 복사해 온 모양의 데이터입니다. 초기 상태로 쓰고 API가 실패하면 setTravelList(images)로 되돌아가요. 그러니까 이 시점의 "목업"은 라이브러리가 아니라 컴포넌트 안의 상수였습니다. 응답 모양은 data.content 배열로 잡아 두었고 경로는 /api/travels/popular/${city}였습니다.
"for BFF"는 커밋 제목에만 있습니다. 코드에 프런트 전용 서버 계층은 없고, 요청은 공통 get을 거쳐 리라이트로 백엔드에 바로 갑니다. 그때 왜 그 단어를 썼는지 커밋에는 설명이 없어요. "화면에 맞춘 API 모양을 먼저 정한다"는 뜻으로 썼던 것 같은데, BFF는 그런 뜻이 아닙니다.
3월 17일 — 배열을 지우고, 경로와 응답이 바뀌었다
b897f13, 제목은 "메인 페이지 msw 제거". 실제 diff는 이렇습니다.
- const [travelList, setTravelList] = useState<TravelItem[]>(images);
+ const [travelList, setTravelList] = useState<TravelItem[]>([]);
@@
} else {
console.error(response.message);
- setTravelList(images);
+ setTravelList([]);
}
배열 두 개(인기 5건·추천 5건)를 지우고 빈 배열로 시작합니다. msw는 이 시점에 package.json에 없었습니다. git log -S '"msw"'로 찾으면 msw가 처음 들어온 커밋은 두 달 뒤인 5월 31일이에요. 그러니까 "msw 제거"는 없는 것을 지웠다고 쓴 제목입니다. 상수 배열을 목업이라 불렀고, 목업이면 msw라고 생각했던 것 같습니다.
같은 커밋에 더 중요한 변화가 두 개 있습니다.
- `/api/travels/popular/${city}`,
+ `/api/travels/popular?city=${city}`,
@@
- `/api/travels/${category}`,
+ `/api/travels/recommend?theme=${theme}`,
경로 파라미터가 쿼리 스트링으로 바뀌었고, 응답도 data.content에서 data로 한 단 얕아졌습니다.
interface HomePopularTravelResponse {
success: boolean;
- data: {
- content: TravelItem[];
- };
+ data: TravelItem[];
13일에 "설계"했다고 적은 API 모양이 17일에 실제로 붙인 모양과 달랐던 거예요. 왜 달라졌는지는 커밋에 없습니다. 다른 목록 API가 페이지 응답이라 content로 감싸는 걸 보고 홈용도 그럴 거라 가정했다가, 고정 개수 응답은 배열 그대로였던 것으로 보이는데 이건 지금의 추정입니다. 커밋에 남은 건 바뀐 결과뿐이에요.
그 밖에 gyongsang을 gyeongsang으로 고친 오타, 이름을 10자에서 자르는 truncateText, 빈 결과 상자 .noData 스타일이 같이 들어갔습니다.
같은 날 밤 — 전역 CSS 한 줄이 다른 슬라이더를 밀었다
ae5f33e는 파일 셋, 2줄 추가 4줄 삭제입니다.
-
-.swiper {
- overflow: visible!important;
-}
global.css에 있던 이 규칙을 지우고 홈 화면의 Swiper 두 개에만 style={{ overflow: 'visible' }}를 줬습니다. 커밋 제목은 "버튼 바 이슈 수정 : swiper 충돌"이에요. 전역으로 .swiper를 잡아 두니 다른 화면의 슬라이더까지 넘쳐서 버튼 줄과 겹쳤던 것으로 읽힙니다. 어느 화면이었는지는 커밋에 없습니다.
검증
- msw가 의존성에 들어온 시점은
git log -S '"msw"' -- package.json으로 확인했습니다. 2025-05-31이 처음입니다. 3월 13일 시점 저장소에mocks디렉터리도 없습니다. - "BFF"는
c6724a4의 커밋 제목에만 있고src/와package.json에는 없습니다. - 경로·응답 모양 변경은
b897f13의homeApi.ts와 컴포넌트 diff에서 확인했습니다. - 화면은 손으로 확인했을 겁니다. 이 시기에 테스트는 없었어요.
남은 것 · 한계
- 커밋 제목이 코드보다 크게 말했습니다. BFF도 msw도 없었어요. 1년 반 뒤 제가 이 커밋을 읽고 처음 한 일이 "msw가 언제 들어왔지"를 찾는 것이었으니, 제목이 틀리면 나중의 나부터 속습니다.
- API 실패 시 빈 배열로 떨어지고 끝입니다. 13일 버전은 실패하면 상수 배열이라도 보여 줬는데, 17일 버전은
console.error하고 "데이터가 없습니다"를 띄웁니다. 실패와 진짜 0건을 사용자가 구분할 수 없어요. - 응답 모양을 프런트가 먼저 정하고 나중에 맞춘 순서는 직짱건강에서 JSON 목업으로 설문을 먼저 만든 것2024-03-31직짱건강 — 백엔드를 기다리지 않고 설문 인터페이스를 먼저 완성한 방법직장인 대상 건강 설문과 위치 기반 병원 추천을 묶은 헬스케어 서비스입니다. 6인 협업 프로젝트에서 프런트엔드로 참여했고, 백엔드 API가 없는 상태에서 JSON 목업으로 설문 플로우를 먼저 완성해 병렬 작업이 가능하게 만든 게 핵심 기여였어요.과 같은 방식입니다. 그때는 그게 팀을 병렬로 돌리는 방법이었고, 여기서는 나흘 뒤 모양이 달라서 다시 맞췄어요. 먼저 만드는 건 맞는데, 맞출 날이 온다는 걸 계산에 넣어야 합니다.
- 전역
.swiper규칙을 인라인 style로 옮긴 건 충돌은 없앴지만 같은 값을 두 컴포넌트에 복사한 것이기도 합니다. 슬라이더가 하나 더 생기면 세 번째 복사가 생겨요.
관련 글: 직짱건강 — 백엔드를 기다리지 않고 설문 인터페이스를 먼저 완성한 방법2024-03-31직짱건강 — 백엔드를 기다리지 않고 설문 인터페이스를 먼저 완성한 방법직장인 대상 건강 설문과 위치 기반 병원 추천을 묶은 헬스케어 서비스입니다. 6인 협업 프로젝트에서 프런트엔드로 참여했고, 백엔드 API가 없는 상태에서 JSON 목업으로 설문 플로우를 먼저 완성해 병렬 작업이 가능하게 만든 게 핵심 기여였어요. · fetch가 Next.js에서 선호되는 이유, 그리고 axios와의 차이점2023-06-01fetch가 Next.js에서 선호되는 이유, 그리고 axios와의 차이점fetch와 axios의 차이를 정리했던 글입니다. 내장 API·번들 크기·SSR 호환이라는 당시 결론은 지금도 유효하지만, 다시 보니 진짜 이유를 놓치고 있었어요 — Next.js App Router는 fetch 자체를 확장해 캐싱·중복 제거를 얹습니다. 실제 프로젝트에서 fetch를 직접 채택하고 래퍼를 만들며 치른 비용까지 붙여서 업데이트했습니다. · 검색은 GET, 목록은 POST2024-09-01검색은 GET, 목록은 POST — 하루에 세 번 바꾼 메서드여행지 목록과 검색 API의 메서드를 하루에 세 번 바꿨습니다. 오후 6시에 둘 다 GET, 7시에 page를 쿼리로, 8시 반에 목록만 POST, 밤 11시 반에 검색은 GET으로 확정. 그런데 POST로 바꾸면서 좌표를 params라는 키로 한 번 감싸서 보냈고, 그걸 다음 날 점심에야 풀었어요. 엿새 뒤 검색도 POST가 됐습니다.