Develop

같은 버그를 두 번 고친 날, V1/V2 이중 스택을 정리하기로 했다

계기: 같은 버그를 양쪽에서 따로 고쳤다

  • 한 화면에 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는 정상 발신 중

  • 의미: 측정 결과가 이상할 때 코드보다 측정 도구를 먼저 의심하는 단계의 존재
  • 이 단계 부재 시: 멀쩡한 저장 로직을 “고치느라” 시간 소모

남는 교훈

이중 스택은 유지 비용이 눈에 잘 안 보인다. 두 벌을 다 돌아가게 유지하는 것 자체는 어렵지 않다.

  • 비용 발생 시점: 버그 수정 시
  • 수반 작업: 어느 쪽을 고칠지 판단 → 종종 양쪽 모두 수정
  • 한쪽 누락 시: 그것이 다음 버그로 전환

“같은 버그를 두 번 고쳤다”는 사건이 통합의 계기가 된 이유:

  • 비용을 처음으로 셀 수 있게 만든 사건
  • 그 전까지의 인식: “언젠가 정리하면 좋겠다” 수준