목록 화면 일곱 개에 같은 수정을 넣었다. 페이지 번호 계산이 틀린 것을 고치는 일이었다. 하나를 열어서 확인하고 전체 확인 완료라고 보고했다. 이틀 뒤 다른 화면에서 같은 증상이 나왔다.
Table of contents
Open Table of contents
원인 — 왜 하나만 봤나
일곱 개가 같은 코드를 쓰는 줄 알았다.
$total = $this->model->count_all();
$this->pagination->initialize([
'total_rows' => $total,
'per_page' => 20,
...
]);
pagination 라이브러리에 total_rows 를 넘기는 이 부분이 공통이니 하나가 되면 다 되는 것으로 봤다. 실제로는 세 개가 조건이 붙은 조회를 쓰고 있었다.
$total = $this->model->count_by_status($status);
수정한 것은 count_all 쪽이었고 count_by_status 를 쓰는 나머지는 안 고쳤다.
같은 문제라고 생각한 것과 실제로 같은 코드인 것은 다르다. 확인하지 않고 같다고 여긴 것이 시작이었다.
목록을 만들고 하나씩 봤다
일곱 개를 적고 각각 확인했다.
[o] 상품 목록 2페이지 정상
[o] 주문 목록 2페이지 정상
[x] 회원 목록 2페이지에서 항목 없음
[x] 문의 목록 2페이지에서 항목 없음
[o] 공지 목록 2페이지 정상
[x] 쿠폰 목록 마지막 페이지 번호 이상
[o] 배송 목록 2페이지 정상
count_by_status 를 쓰는 세 개가 그대로 남아 있었다. 목록을 안 만들었으면 다 봤다고 생각하고 넘어갔을 것이다.
적어 놓고 하나씩 지우니 안 본 것이 드러난다. 다 봤다는 말이 목록이 다 지워졌다는 뜻으로 바뀌었다.
무엇을 보면 통과인지 정했다
확인했다는 말이 사람마다 다른 뜻이었다. 기준을 정했다.
1. 1페이지가 나온다
2. 2페이지로 넘어가고 항목이 나온다
3. 마지막 페이지 번호가 (전체 건수 / 20)의 올림과 같다
4. 마지막 페이지에서 항목이 나온다
5. 조건을 걸었을 때도 1~4가 성립한다
5번이 이번에 놓친 부분이었다. $status 를 걸지 않고만 봤다.
기준이 있으면 확인이 반복 가능해진다. 다른 사람이 해도 같은 결과가 나온다.
확인하다 보니 전체 건수에 따라 결과가 달랐다.
20건 이하 1페이지만 나옴
정확히 20건 2페이지 번호가 나오는데 빈 페이지
21건 정상
딱 떨어질 때 빈 2페이지가 생기는 것이 원래 있던 문제였다.
$totalPage = ceil($total / $perPage);
ceil(20 / 20) 은 1이니 맞다. 문제는 다른 화면이었다.
$totalPage = floor($total / $perPage) + 1;
floor 로 내림하고 1을 더하면 20을 20으로 나눌 때 2가 된다. 같은 계산이 화면마다 다르게 돼 있었다.
한 곳으로 모은 계산
ceil 과 floor 가 화면마다 섞여 있는 것이 근본 원인이었다. 같은 계산이 복사돼 있었기 때문이다.
// helpers/paging_helper.php
function total_pages($total, $perPage) {
if ($perPage <= 0) return 1;
return max(1, (int)ceil($total / $perPage));
}
일곱 화면이 total_pages 를 쓰게 했다. 한 곳만 맞으면 전부 맞는다.
$perPage 가 0일 때를 넣은 것은 config 에서 0이 들어온 적이 있어서다. 그때 Division by zero 가 났다.
다음에 페이지 관련 수정을 할 때 볼 수 있게 확인 항목도 적어 뒀다.
페이지 처리 확인 항목
- 대상 화면 7개 (상품/주문/회원/문의/공지/쿠폰/배송)
- 건수별: 0건, 20건 미만, 정확히 20건, 21건, 100건 이상
- 조건 유무 각각
전체 확인이라고 쓰는 대신 이 목록을 채운 결과를 남긴다. 무엇을 봤고 무엇이 나왔는지가 보이니 읽는 사람이 내 말을 믿을지 정하지 않아도 됐다.
정리
- 표본 하나가 통과한 것은 나머지가 통과한다는 뜻이 아니다
- 같은 문제라고 생각한 것과 실제로 같은 코드인 것은 다르다
- 대상을 목록으로 적고 하나씩 지운다. 안 적으면 다 봤다고 생각한다
- 무엇을 보면 통과인지 기준을 정한다. 없으면 사람마다 다른 뜻이 된다
- 경계값을 조건에 넣는다. 정확히 한 페이지 분량일 때가 자주 어긋난다
floor에 1을 더하는 식과ceil은 딱 떨어질 때 갈린다- 같은 계산이 여러 곳에 있으면 한 곳으로 모은다
- 전체 확인이라고 쓰는 대신 채운 목록을 남긴다