상품 복제 기능을 만들었더니 복제한 상품에 옵션이 없다는 문의가 왔다. 코드는 상품 행 하나만 복제하고 있었다.
Table of contents
Open Table of contents
행 하나만 복제한 결과
옵션과 이미지와 분류 연결과 재고가 전부 딸려 있는데 아무것도 따라가지 않았다. 복제라는 말이 무엇을 뜻하는지가 정해지지 않은 채로 구현된 상태였다.
행을 복사하는 것은 기술적으로 쉽지만 무엇까지 복제할지는 설계 결정이다. 그 결정을 안 하면 가장 좁은 범위로만 동작한다.
딸린 것을 찾는 방법
이 테이블을 참조하는 관계를 메타데이터로 뽑으려 했는데 외래키가 걸려 있지 않아 아무것도 안 나왔다. 그래서 참조에 쓰이는 컬럼 이름으로 전체 스키마를 훑어 아홉 개를 찾았다.
외래키가 있으면 관계로 찾고 없으면 컬럼 이름으로 찾는다. 관계 정의가 없다는 것이 딸린 것이 없다는 뜻은 아니었다.
복제할 것과 아닌 것
아홉 중 넷만 복제 대상이었고 나머지는 복제하면 안 되는 것이었다. 주문 이력과 후기와 조회 기록과 가격 변경 이력과 통계가 그쪽이었다.
새 상품에 옛 주문이 붙거나 남이 쓴 후기가 붙으면 데이터가 거짓이 되므로 이력과 남이 만든 것은 복제 대상이 아니다. 복제한다는 말의 범위를 이렇게 명시하고 나서야 구현이 정해졌다.
그대로 두면 안 되는 값
행을 그대로 복사하면 문제가 되는 컬럼도 있었다. 고유 코드는 겹치면 안 되고 이름에는 구분 표시가 필요하며 생성 시각과 조회 수와 판매 수는 새로 시작해야 한다.
가장 중요한 것이 판매 상태였는데 판매 중인 채로 복제되면 복제하자마자 팔린다. 이미지도 파일까지 복사해야 하는데 파일을 공유하면 한쪽을 지울 때 다른 쪽 이미지가 함께 사라진다.
트랜잭션 범위와 분류 강제
데이터베이스 작업은 한 트랜잭션으로 묶어서 중간에 실패했을 때 반쯤 복제된 상품이 안 남게 했다. 파일 복사는 오래 걸리므로 트랜잭션 밖에서 따로 처리했는데 실패하면 이미지 없는 상품이 남고 그것은 다시 시도하면 된다.
어느 상품에서 복제했는지를 컬럼으로 남기니 복제로 만들어진 것이 얼마나 되는지 셀 수 있었고 원본을 고칠 때 복제본을 함께 봐야 하는지 물어볼 근거가 됐다. 새 연관이 생겼을 때 복제 대상인지 분류하지 않으면 시험이 실패하게 만들어서 판단이 빠지지 않게 했다.
정리
- 행을 복제하면 그것을 가리키는 것들도 함께 봐야 한다
- 무엇까지 복제할지는 기술이 아니라 설계 결정이다
- 외래키가 없으면 컬럼 이름으로 딸린 것을 찾는다
- 관계 정의가 없다는 것이 딸린 것이 없다는 뜻은 아니다
- 이력과 남이 만든 것은 복제하면 데이터가 거짓이 된다
- 판매 상태를 그대로 두면 복제하자마자 팔린다
- 파일을 공유하면 한쪽 삭제가 양쪽을 지운다
- 새 연관이 분류되지 않으면 시험이 실패하게 만든다