동기화가 안 되는 상품이 있어서 원인을 찾으려고 MySQL 조회에 조건을 하나 넣었다.
$rows = $this->db->where('status', 'normal')->get('product')->result();
정상 상품만 보려고 넣은 것이었는데 원인을 찾고 나서 그 줄을 안 지웠다.
Table of contents
Open Table of contents
조사용이 로직이 됐다
한 달쯤 뒤에 판매 중지 상품이 동기화가 안 된다는 문의가 왔다. 당연했고 status = 'normal' 만 대상이니 중지 상품은 안 들어간다.
원래는 product 전부가 대상이었는데 조사할 때 범위를 좁힌 것이 그대로 남았다. 조사용 조건과 로직상 필요한 조건이 코드에서 구분이 안 되고 둘 다 그냥 where 다.
나중에 그 where 를 보는 사람은 그 조건에 이유가 있을 것으로 본다. 그래서 지우지 않고 그대로 두게 되고 시간이 지나면 그것이 정상 동작이 된다.
표시를 남기기로 했다
조사용으로 넣는 것에 표시를 붙였다.
// TEMP 2016-06-19 원인 조사용. 확인 후 제거
$rows = $this->db->where('status', 'normal')->get('product')->result();
TEMP 로 검색하면 나온다.
$ grep -rn "TEMP " --include=*.php application/
배포 전에 이것을 돌려서 남은 것이 있는지 본다.
검사에 넣었다
사람이 기억해서 grep 을 돌리는 것은 빠뜨리므로 배포 스크립트에 넣었다.
CNT=$(grep -rn "TEMP " --include=*.php application/ | wc -l)
if [ "$CNT" -gt 0 ]; then
echo "임시 코드가 남아 있습니다 (${CNT}건)"
grep -rn "TEMP " --include=*.php application/
exit 1
fi
남아 있으면 exit 1 로 배포가 멈춘다. 처음에 돌렸더니 네 건이 나왔고 전부 몇 달 전에 넣은 것들이었다.
사람이 기억해서 지우는 것에 기대지 않고 구조가 막게 만드는 것이다.
검증 — 검사가 대상을 보고 있는가
검사를 넣고 나서 그것이 실제로 무엇을 보고 있는지도 확인했다. 통과했다는 결과만으로는 대상을 제대로 훑었는지 알 수 없다.
TOTAL=$(find application -name "*.php" | wc -l)
if [ "$TOTAL" -eq 0 ]; then
echo "대상 파일이 없습니다. 경로 확인"
exit 1
fi
echo "대상 ${TOTAL}개 파일 검사"
find 가 준 TOTAL 이 0이면 경로가 틀린 것이고 그것이 임시 코드 없음으로 읽히면 안 된다.
grep 은 이 둘을 종료 코드로 갈라 준다. 찾는 것이 없어서 0건이면 1이 오고 경로가 없어서 못 훑었으면 2가 온다.
화면에 찍히는 것은 양쪽 다 없어서 눈으로는 구분이 안 된다. 경고를 지우려고 표준 오류를 버려 두면 그 단서마저 사라진다. 실제로 경로를 잘못 줘서 아무것도 안 보고 있던 적이 있었다.
코드를 안 고치는 방법과 커밋 분리
애초에 코드를 안 고치면 남을 것도 없다. 세 가지를 봤다.
먼저 조회로 확인하는 것이다. 코드에서 where 를 넣는 대신 GROUP BY 로 직접 본다.
SELECT status, COUNT(*) FROM product GROUP BY status;
다음은 log_message 로 확인하는 것이다. 조건을 바꾸는 대신 값을 찍는다.
log_message('debug', "동기화 대상: " . count($rows) . "건, 상태별: " . json_encode(array_count_values(array_column($rows, 'status'))));
로그는 남아도 로직을 안 바꾸고 수준을 낮게 두면 운영에서 안 찍힌다. 마지막은 대상을 안 좁히고 결과를 거르는 것으로 조회는 그대로 두고 화면에 찍을 때만 거른다.
세 가지 중에 두 번째를 주로 썼는데 log_message 는 남겨도 부작용이 없다.
그래도 코드를 고쳐야 할 때가 있는데 그때는 원래 줄을 지우지 않고 남겼다.
// TEMP 2016-06-19 원인 조사. 아래 원본으로 되돌릴 것
// $rows = $this->db->get('product')->result();
$rows = $this->db->where('status', 'normal')->get('product')->result();
되돌릴 때 주석을 풀면 되고 원래가 무엇이었는지 기억 안 나서 못 되돌리는 일이 없다. 다만 이것도 오래 두면 안 되고 확인이 끝나면 바로 되돌린다.
조사용 변경과 실제 수정을 한 커밋에 넣으면 되돌리기 어렵다. 조사할 때는 svn commit 을 안 하고 원인을 찾으면 조사용을 되돌린 뒤 수정만 커밋했다.
$ svn status
M application/models/product_model.php ← 조사용? 수정?
M application/controllers/sync.php
작업 사본에 조사용이 남은 채로 다른 것을 커밋하면 같이 들어가므로 커밋 전에 무엇이 바뀌어 있는지 봤다.
정리
- 조사하려고 넣은 조건을 안 지우면 그것이 로직이 된다
- 코드에서는 조사용과 필요한 조건이 구분되지 않는다
- 나중에 보는 사람은 이유가 있을 것으로 본다
- 조사용에 표시를 붙이고 배포 전에 검사해 남아 있으면 멈춘다
- 사람이 기억하는 것에 기대지 않고 구조가 막게 한다
- 검사가 대상을 보고 있는지 개수와 종료 코드로 확인한다
grep은 0건이면 1이고 경로가 없으면 2인데 화면 출력으로는 같다- 애초에 코드를 안 고치는 방법을 먼저 본다
- 조회나 로그로 확인하면 남을 것이 없다
- 고쳐야 하면 원래 줄을 주석으로 남겨 되돌리기 쉽게 한다
- 조사용 변경과 실제 수정을 다른 커밋으로 나눈다