계기: 같은 버그를 양쪽에서 따로 고쳤다
- 한 화면에 V1·V2 두 벌의 구현 공존
- 신규 작성 화면 — V2 사용
- 월 업데이트 화면 — V1 사용
카테고리 상태 desync 버그 발생 시의 대응:
- V1 쪽 수정 → 며칠 뒤 V2 쪽에서 재수정
- 같은 원인·같은 증상·같은 수정의 2회 반복
- 이 시점에 “이중 스택 유지 비용”이 명확한 숫자로 표면화
Phase 0~5로 나눠 통합했다
- 한 번에 갈아엎지 않고 6단계로 분할
- 목표 — 월 업데이트 화면을 V2 스택으로 이관
| Phase | 내용 |
|---|---|
| 0-1 |
isUpdate·updateMonth props 배선, 수집월 폴백 |
| 2 | 다중 카테고리 저장 + sticky mount |
| 3 | 카테고리 편집 차단·월 기준 표시·리본 경고 |
| 4 | 사이드패널 접기 |
| 5 | V1 스택 제거 |
핵심은 Phase 1의 성질.
- 호출부가
isUpdate미전달 시 기본값false→ 생성·수정 화면 동작 그대로 - 배선만 깔고 아무것도 안 바꾸는 단계를 선행 배치 → 롤백 용이
Phase 5 삭제 규모와 주의점:
- V1 전용 파일 6개, 2,389줄 삭제
- 조심한 것 — 공용 부품
- 잔존 대상 5개 —
AllocationScopePickerModal,DataIOButtonGroups,DataIOTableWrapper등. V2도 import 중 - 그중 하나는 다른 화면 2곳에서도 사용 중
“V1 디렉토리에 있으니 V1 것”이라는 가정 — 성립하지 않음
통합 과정에서 드러난 숨은 결함 4종
두 스택 병렬 비교 시 드러난, 한쪽에만 있던 결함들:
1) 엑셀 업로드가 replace로 동작했다
- 헤더의 엑셀 업로드 input이
uploadExcel호출 시 세 번째 인자(isUpdatedOrAdded) 누락 - 결과 — 업로드가 append가 아니라 replace로 처리
- 증상 — 6월 데이터가 있는 상태에서 7월 엑셀을 올리면 6월 데이터 소실
2) 거짓 저장 성공 보고
- 저장 후 “N건 저장됨” 토스트 표시
- 이 N의 실체 — 실제 전송 건수가 아니라 전송 시도 건수
- 일부 실패해도 전체 건수 그대로 표시 → 사용자는 저장 완료로 믿고 화면 이탈
3) 빈 카테고리 편집분 무경고 유실
- 특정 조건에서 편집 내용이 아무 경고 없이 소실
4) 저장 함수가 실패해도 true를 반환했다
- 가장 근본적인 결함
- 저장 함수의 반환값이 성공 여부 미반영
- 2번의 거짓 보고도 결국 여기서 파생
네 개 다 “이중 스택이라서 생긴 버그”는 아니다.
- 실체: 한쪽 스택에만 있던 결함
- 발견 경로: 통합을 위해 두 구현을 나란히 읽는 과정에서 차이가 노출
트랜잭션이 없는 상태에서의 부분 실패 설계
- 저장 API가 한 번에 하나만 수신하는 구조
- 다중 카테고리 저장 → N회 순차 호출 필요 → 중간 실패 가능
문제는 트랜잭션이 없어서 롤백이 불가능하다는 것이다.
- 3건 중 2건 저장 + 3번째 실패 → 앞의 2건 복구 수단 부재
- 정석은 BE 배치 API 요구 → 일정상 불가
그래서 “실패를 숨기지 않는” 방향으로 설계:
- 실패 항목 명시 — “N건 저장됨”이 아니라 실패 항목 나열
- 검증 실패와 서버 실패 구분 — 입력값 오류는 사용자 수정 대상, 서버 오류는 재시도 대상. 대응이 다르므로 메시지도 분리
- 비가역적 다음 단계 진입 차단 — 부분 실패 상태에서 마감 같은 동작 진행 금지
차선책: 일관성 보장이 불가능하다면 최소한 불일치 상태를 사용자가 인지하고 수동 복구 가능하게 구성
자기 계측 오류를 정정한 기록
PR 기록에 남은 인상적인 대목:
- 검증 중 계측 결과 — “POST 요청이 0건”
- 해석 — 저장이 아예 안 되고 있다는 뜻이라 심각하게 취급
그런데 이후 정정이 올라왔다. 계측 자체가 틀렸던 것이다.
- 원인 — 네트워크 요청 캡처 정규식이
[A-Z_]+패턴 → 소문자가 섞인 URL 전량 누락 -
실제 — POST는 정상 발신 중
- 의미: 측정 결과가 이상할 때 코드보다 측정 도구를 먼저 의심하는 단계의 존재
- 이 단계 부재 시: 멀쩡한 저장 로직을 “고치느라” 시간 소모
남는 교훈
이중 스택은 유지 비용이 눈에 잘 안 보인다. 두 벌을 다 돌아가게 유지하는 것 자체는 어렵지 않다.
- 비용 발생 시점: 버그 수정 시
- 수반 작업: 어느 쪽을 고칠지 판단 → 종종 양쪽 모두 수정
- 한쪽 누락 시: 그것이 다음 버그로 전환
“같은 버그를 두 번 고쳤다”는 사건이 통합의 계기가 된 이유:
- 비용을 처음으로 셀 수 있게 만든 사건
- 그 전까지의 인식: “언젠가 정리하면 좋겠다” 수준