상품 이미지 변환에 출력이 일정 크기를 넘으면 -quality 를 낮춰 다시 인코딩하는 동적 압축이 들어 있었다. 채널의 업로드 제한 10MB 를 지키려고 넣은 것인데 이것이 실제로 필요한지를 검증했다.
Table of contents
Open Table of contents
배경 — 표본이 만든 편향
먼저 media_files 를 ORDER BY size DESC 로 정렬해 가장 큰 것부터 확인했다. 제한을 넘는 것이 하나도 없었고 가장 큰 것도 그 3분의 1에 못 미쳤다.
그런데 그렇게 뽑은 표본이 PNG 하나에 몰려 있는 것이 보였다. 크기 역순으로 뽑으니 그 형식이 위쪽에 몰린 것이고 JPEG 고해상도 원본은 보지 못한 편향된 결론이었다.
검증 — 다시 뽑은 표본
그래서 identify 로 잰 고해상도 JPEG 원본 60개를 골라 다시 검증했다. 그 원본들은 파일 자체가 수 메가바이트로 꽤 큰 것들이었다.
변환 결과를 확인해 보니 여전히 제한을 넘는 것이 하나도 없었다. 정렬 기준이 다른 축의 편향을 만들 수 있으므로 표본을 다시 뽑아 확인한 것이 이 검증에서 중요한 지점이었다.
조치 — 산술로 낸 상한
표본에서 0건이 나왔지만 우연히 없는 것과 구조적으로 불가능한 것은 다른 얘기다. 그래서 상한이 얼마인지를 직접 계산해 봤다.
변환 규칙이 -resize 로 짧은 축을 일정 범위로 제한하고 긴 축과의 비율에 상한을 두고 있으므로 최대 픽셀 수가 정해진다. 인코딩 품질에서 픽셀당 비트 수가 대략 정해지므로 둘을 곱하면 출력 용량의 상한이 나오고 그 값이 제한의 3분의 1 수준이었다.
원인 — 둘이 함께 필요한 이유
표본만으로 말할 수 있는 것은 지금까지 안 넘었다는 것까지이고 내일 넘을 수도 있다. 산술만으로는 비트 밀도 가정이 실제로 맞는지를 알 수 없다.
실측이 산술을 뒷받침하고 산술이 실측을 일반화하므로 둘이 같이 있어야 확정된다. 그 조건이 참이 될 수 없으므로 동적 압축은 발동할 수 없는 죽은 안전망이었다.
주의 — 제거와 남긴 관계식
두 가지 방법이 있었다. 코드를 남기고 발동하면 로그만 찍게 하는 것과 제거하는 것이다. 뒤쪽을 골랐다. 이유는 발동할 수 없다는 것이 산술로 확정돼서다. 대신 규칙을 바꿀 때 안전망을 다시 넣어야 하는 것을 감수했다. 동적 압축을 제거하고 -quality 85 로 고정하며 관련 설정과 잔재를 함께 지웠다. 죽은 코드는 그냥 안 도는 것이 아니라 읽는 사람이 매번 왜 있는지를 생각하게 하고 리팩터링할 때 유지 대상이 된다.
이때 쓴 계산 관계는 일회성으로 버리지 않고 IMAGE_PIPELINE.md 에 남겨 뒀다. 픽셀 수와 비트 밀도를 곱하면 출력 용량 상한이 나오므로 짧은 축 상한이나 비율 상한이나 품질을 바꿀 때 사전에 계산할 수 있고 넘을 것 같으면 그때 안전망을 다시 넣으면 된다.
정리
- 안전망이 실제로 발동할 수 있는지 검증한다
- 표본만으로는 지금까지 안 넘었다는 것까지다
- 산술로 상한을 계산하면 구조적 한계가 나온다
- 표본과 산술이 같이 있어야 확정된다
- 발동할 수 없는 코드는 죽은 안전망이므로 제거한다
- 산술 관계를 남기면 규칙을 바꿀 때 사전 계산할 수 있다
- 정렬 기준이 다른 축의 편향을 만들 수 있다
- 표본을 다시 뽑아 확인한다