한 번에 여러 상품을 가져오는 화면에서는 성공 건수가 먼저 눈에 들어온다. 그런데 어떤 입력을 성공으로 센 것인지 확인하지 않으면 숫자는 업무의 완료를 설명하지 못한다. 나는 기존 CSV 등록 경로의 네 반례를 재현한 뒤, 파일을 읽지 못한 실패와 한 행의 잘못된 값을 서로 다른 지점에서 멈추도록 고쳤다.

성공 한 건이라는 표시부터 다시 의심했다

원래 프로그램의 CSV 경로를 실제 코드에서 떼어 읽고 등록 콜백과 상태 표시를 대역으로 연결했다. 닫히지 않은 따옴표, 여분의 열, 문자가 섞인 가격, 음수 가격을 각각 넣자 네 경우 모두 등록 콜백이 한 번 호출되고 성공 한 건으로 집계됐다. 실제 외부 상품을 등록한 실험이 아니라 입력 처리의 조건을 재현한 결과다.

문자가 섞인 12oops34는 1234로 바뀌었다. 숫자가 아닌 문자를 지워 주면 편리해 보이지만 원래 입력과 다른 금액을 만들어 버릴 수 있다. 음수도 참으로 평가되는 숫자라서 단순히 값이 있는지만 검사하는 조건을 통과했다. 자료를 읽어 주는 편의와 자료의 뜻을 고치는 판단을 같은 함수에 맡기지 않기로 했다.

파일 전체의 구문 오류는 첫 행을 만들기 전에 멈췄다

따옴표가 닫히지 않으면 그 뒤의 쉼표와 줄바꿈을 어디까지 같은 셀로 읽어야 하는지 달라진다. 이것은 한 행의 가격이 잘못된 것과 다르다. 앞부분에 정상처럼 보이는 행이 있더라도 파일 전체가 올바르게 나뉘는지 먼저 확인해야 했다. 수정한 경로는 전체 CSV를 해석한 다음에야 등록 반복문으로 들어간다.

실제 회귀 검사에는 정상 행 뒤에 닫히지 않은 따옴표가 있는 자료를 넣었다. 기대는 앞의 한 건이라도 먼저 생성하는 것이 아니라 등록 콜백 호출이 전혀 없는 것이다. 따옴표 뒤에 허용되지 않은 글자가 붙거나 일반 셀 중간에 따옴표가 끼어 있는 경우도 구문 오류로 거절했다. 부분 성공을 어디까지 허용할지 정하려면 먼저 오류가 속한 경계를 나눠야 했다.

나눠 읽을 수 있는 행의 오류는 따로 집계했다

파일을 올바르게 나눴다면 그다음에는 각 행의 의미를 검사한다. 원래 화면은 다섯 열의 헤더와 자료를 받는다. 앞의 다섯 값만 사용하고 여분의 열을 버리던 처리를 바꿔 헤더와 행의 열 개수를 확인했다. 열이 모자라거나 많은 데이터 행은 실패 목록에 남기고, 다른 정상 행은 기존 순차 처리 방식으로 넘긴다.

이 방식은 파일 전체의 원자적 저장을 구현한 것이 아니다. 정상 행이 실제 등록 단계에서 실패할 수도 있고, 앞의 정상 행이 처리된 뒤 다음 콜백이 예외를 낼 수도 있다. 이번 수정은 구문 오류 이전의 불필요한 생성을 막고 행별 입력 실패를 구별한 범위다. 재시도나 전부 되돌리기가 필요하다면 확인된 결과와 중복 요청, 저장 경계를 별도로 설계해야 한다.

금액을 고쳐 주는 대신 허용한 숫자만 받았다

가격은 양의 유한 숫자만 받도록 했다. 단순 숫자와 소수, 올바른 세 자리 쉼표 묶음을 허용하고 문자·단위·통화기호·부호를 임의로 제거하지 않는다. 지원하지 않는 표기라면 담당자가 확인해 다시 입력하도록 남긴다. 어느 나라 가격인지나 실제 환율을 이 검사로 추정하지 않는다.

정상 입력도 함께 보존해야 했다. 템플릿처럼 따옴표로 감싼 쉼표, 줄바꿈, 이중 따옴표, 파일 앞의 BOM과 CRLF를 검사했다. 잘못된 자료를 막는 수정이 정상적인 상품명과 옵션을 잘라 내면 다른 문제를 만들기 때문이다. 성공 조건은 오류 입력이 멈춘다는 것과 지원하던 정상 입력이 그대로 전달된다는 두 가지였다.

검사 대상과 운영 자료를 다른 곳에 두었다

별도의 개발 단계에서 원본의 순수 함수와 실제 CSV 핸들러를 사용하는 검사 19개를 통과했다. 등록 콜백과 상태 표시는 대역이다. G드라이브의 격리 빌드와 별도 데이터·포트를 쓰는 기존 목업 API 검사 26개도 확인했다. 실제 공급자나 메일, 발주가 성공했다는 뜻으로 이 숫자들을 더하지 않았다.

원래 운영 자료와 빌드 등을 포함한 보호 대상 111개 파일의 바이트와 수정 시각을 대조했다. 수정 전후 소스를 묶은 열한 파일을 실제로 풀고 복구한 소스에서도 같은 CSV 검사 19개를 실행했다. 원래 실행본은 교체하지 않았고 새 빌드는 격리 폴더에 남겼다. 이번 콘텐츠 작업에서는 그 실제 기록을 읽었으며 원제품 시험을 다시 실행하지 않았다.

공유 예제는 등록 프로그램 대신 검토 결과를 만든다

기존 자료 가져오기 모듈은 이미 해석된 행의 중복·누락과 수정 충돌을 다룬다. 상품 후보 모듈은 원문에서 읽은 값과 제공된 값의 출처를 나눈다. 둘 다 CSV 원문을 올바르게 나누는 부품은 아니었다. 그래서 이번에는 그 앞단의 구문과 행별 검토에 한정한 독립 합성 예제를 만들고 두 기존 모듈을 별도 책임으로 연결했다.

새 예제는 실제 상품 주소나 업체 자료 없이 세 열만 사용한다. 금액을 두 자리 소수의 정수 단위로 바꾸는 규칙과 크기 제한도 명시했다. 이 규칙은 원래 앱의 숫자 계약보다 좁으며 그 앱에 설치한 변환기가 아니다. 정상 후보가 있어도 실제 등록 수는 항상 0이다. 결과를 읽는 뷰어와 파서 실행, 후보 생성과 저장 완료를 구별해 가져가길 바란다.