상위 상품을 수정할 때마다 같은 이미지가 매번 재업로드되고 있었다. 비용 문제라 멱등하게 만들면 되는 일로 보였다.
Table of contents
Open Table of contents
잘못 말한 책임 경계
처음에는 요청 쪽이 재업로드 여부를 판단한다고 설명했다가 지적을 받았다. 다시 보니 판단은 처리 담당 쪽이 하고 있었다.
if ($existing && $existing->file_hash === $hash) {
return $existing; // 같으면 재사용
}
처리 쪽에 파일 해시로 같은지 판단하는 멱등 로직이 이미 구현돼 있었다. 없는 것을 만들어야 하는 상황이 아니라 있는 것이 왜 안 먹는지를 봐야 하는 상황이었다.
멱등이 서는 전제
로직이 있는데 왜 안 먹는지를 보려고 그 로직의 전제를 봤다.
Media::where('model_id', $modelId)->where('collection_name', $collection)
이 조회가 옛 레코드를 찾을 수 있어야 재사용 분기로 들어간다. 즉 모델 식별자가 불변이어야 멱등이 성립한다. 해시 비교 로직은 그 전제 위에서만 의미가 있다.
대상마다 다른 결과
두 종류를 비교하니 결과가 갈렸다. 대표와 부가 이미지는 상품 식별자를 쓰는데 상품 식별자는 수정해도 안 바뀌므로 옛 레코드를 찾고 멱등이 그대로 동작한다.
본문 이미지는 본문 콘텐츠 식별자를 쓰는데 이 시스템은 수정할 때마다 새 본문 식별자를 발행한다. 새 식별자로는 옛 레코드를 찾을 수 없으므로 멱등이 원리적으로 성립하지 않는다. 같은 로직인데 한쪽에서만 동작하는 이유가 전제에 있었다.
요청 쪽으로 옮기면 안 되는 이유
그러면 요청 쪽에서 판단하자는 생각이 들 수 있는데 그러면 안 된다. 판단 로직이 두 곳에 생기고 처리 쪽이 이미 하는 것을 또 하게 되며 두 벌이 시간이 지나면 갈린다.
책임은 처리 쪽에 있으므로 거기서 안 되는 이유를 없애야 한다. 본문 이미지는 옛 레코드를 새 식별자로 이어 붙이거나 본문 콘텐츠를 새로 발행하지 않고 제자리 갱신하는 두 방법이 있다. 뒤쪽이 근본적인데 새 식별자를 발행하는 이유가 롤백 때문이라 롤백 설계를 같이 바꿔야 한다.
비효율과 틀림의 구분
여기서 판단이 하나 필요했다. 재업로드가 오동작인지 아닌지다.
결과는 맞고 같은 이미지가 다시 올라갈 뿐이므로 오동작이 아니라 비용 문제였다. 그래서 병합을 막는 사유가 아니라고 명시했다. 비효율과 틀림을 구분하지 않으면 전부 급한 일이 된다.
최종 정리도 그 형태로 적었다. 처리 쪽 멱등 로직은 이미 구현돼 있고 요청 쪽 배선과 본문 식별자 안정화가 미구현이다. 멱등을 구현해야 한다고 적는 것과 이 둘이 미구현이라고 적는 것은 다른 작업 지시가 된다.
이 정리는 내가 틀리게 말했다가 지적받고 다시 잡은 결과다. 요청 쪽이 판단한다는 전제로는 요청 쪽에 로직을 넣자는 답이 나오는데 그것은 이미 있는 것을 한 벌 더 만드는 일이었다. 틀린 전제가 틀린 작업을 만든다.
정리
- 멱등 로직이 어느 쪽 책임인지 먼저 확정한다
- 멱등은 옛 레코드를 찾을 수 있다는 전제 위에 선다
- 식별자가 매번 새로 발행되면 멱등이 원리적으로 성립하지 않는다
- 판단을 다른 쪽으로 옮기면 두 벌이 생기고 시간이 지나면 갈린다
- 같은 문제여도 대상마다 작업 규모가 다르다
- 비효율과 틀림을 구분하지 않으면 전부 급한 일이 된다
- 구현해야 한다가 아니라 이것이 미구현이라고 적는다
- 틀린 전제가 틀린 작업을 만든다