기간 할인을 손보려고 grep -rn 으로 관련 코드를 찾았다. LimitedDiscount 라는 모델이 있었다. 열어 보니 기간 할인만 다루는 것이 아니었다.
Table of contents
Open Table of contents
여러 용도가 한 모델에 들어 있었다
컬럼을 봤다.
CREATE TABLE limited_discount (
discount_no INT NOT NULL AUTO_INCREMENT,
product_no INT NOT NULL,
rate INT NOT NULL,
start_date DATETIME NULL,
end_date DATETIME NULL,
coupon_code VARCHAR(30) NULL,
member_grade INT NULL,
event_no INT NULL,
...
);
기간을 담는 start_date 와 end_date 말고도 쿠폰과 회원 등급과 이벤트가 붙어 있다. 처음에는 기간 할인용이었는데 나중에 다른 할인이 생길 때마다 coupon_code 와 member_grade 와 event_no 가 붙은 것이다.
이름이 판단을 흐렸다
이름이 LimitedDiscount 니까 기간 할인만 여기 있다고 생각했다. 쿠폰 할인을 찾으려고 다른 데를 뒤졌는데 없었다. coupon_code 컬럼과 함께 여기 있었다.
이름이 옛 용도를 가리키면 찾는 사람이 다른 데를 본다. 이름이 정확하면 grep 한 번에 끝날 탐색이 이름이 어긋나 있으면 한참 걸린다.
무엇이 들어 있는지 세어 봤다
SELECT
SUM(coupon_code IS NOT NULL) AS coupon,
SUM(member_grade IS NOT NULL) AS grade,
SUM(event_no IS NOT NULL) AS event,
SUM(coupon_code IS NULL AND member_grade IS NULL AND event_no IS NULL) AS period_only,
COUNT(*) AS total
FROM limited_discount;
coupon grade event period_only total
1204 891 340 2118 4553
period_only 가 2118로 절반이 안 된다. 이름이 가리키는 것이 소수인 상태였다. 코드를 읽는 것만으로는 이 비율을 알 수 없고 COUNT(*) 를 돌려 봐야 나온다.
판단 기준 — 나눌지 합칠지
세 가지를 봤다. 그대로 두고 이름만 Discount 로 바꿀 수 있다. 그러면 클래스와 테이블 이름을 쓰는 곳을 다 고쳐야 한다. 유형별로 PeriodDiscount 와 CouponDiscount 로 나눌 수도 있다. 깔끔하지만 공통 로직이 흩어진다. 하나로 두되 유형 컬럼으로 가르는 방법도 있다.
세 번째로 했다. 할인 금액을 계산하는 방식은 거의 같았고 WHERE 조건만 달라서 PeriodDiscount 쪽으로 나누면 중복이 생긴다.
ALTER TABLE limited_discount
ADD COLUMN discount_type VARCHAR(20) NOT NULL DEFAULT 'period' AFTER product_no;
기존 행에 유형을 채웠다.
UPDATE limited_discount SET discount_type = 'coupon' WHERE coupon_code IS NOT NULL;
UPDATE limited_discount SET discount_type = 'grade' WHERE member_grade IS NOT NULL;
UPDATE limited_discount SET discount_type = 'event' WHERE event_no IS NOT NULL;
순서가 중요해서 여러 조건이 겹치는 행이 있는지 먼저 봤다.
SELECT COUNT(*) FROM limited_discount
WHERE (coupon_code IS NOT NULL) + (member_grade IS NOT NULL) + (event_no IS NOT NULL) > 1;
-- 0
0이라 UPDATE 순서와 무관했다. 겹치는 것이 있었으면 어느 유형인지 정해야 했다. discount_type 한 컬럼으로는 못 담는 경우도 나왔을 것이다.
이름 교체와 주석
테이블 이름을 바로 안 바꿨다. 쓰는 곳이 60군데였다.
class Discount_model extends CI_Model {
protected $table = 'limited_discount'; // 옛 테이블 이름
...
}
// 옛 이름 유지 (당분간)
class Limited_discount_model extends Discount_model {}
새로 짜는 코드는 Discount_model 을 쓰고 옛 코드는 Limited_discount_model 로 그대로 돈다. 한 달 뒤에 옛 이름을 쓰는 곳이 남았는지 봤다.
$ grep -rln "Limited_discount_model" --include=*.php application/
grep -rln 에 12곳이 남아서 하나씩 바꿨고 전부 없어진 뒤에 별칭 클래스를 지웠다.
이름과 실제가 달라진 경위를 주석에 쓸까 했는데 안 썼다. 원래 기간할인용이었으나 어느 해에 쿠폰이 추가됐다는 식의 주석은 계속 낡는다. 이력은 커밋 메시지가 담을 일이다.
/**
* 할인 모델. discount_type 으로 유형을 구분한다.
* period 기간 할인 (start_date ~ end_date)
* coupon 쿠폰 할인 (coupon_code)
* grade 등급 할인 (member_grade)
* event 이벤트 할인 (event_no)
*/
지금 무엇인지만 적었다.
이름과 실제가 어긋난 것이 더 있는지도 봤다. 테이블 이름에 특정 개념이 든 것을 골라 그 개념 밖의 컬럼이 있는지 보는 방식이다.
member_point → 포인트 말고 쿠폰, 등급 정보도 있음
order_delivery → 배송 말고 반품 정보도 있음
product_review → 후기 말고 문의도 있음
세 개가 더 나왔고 product_review 가 특히 심했다. 후기와 문의가 한 테이블에 있고 유형 컬럼도 없어서 목록으로 적어 두고 손댈 일이 있을 때 같이 정리하기로 했다.
정리
- 만든 목적과 지금 쓰이는 곳이 다르면 이름이 사실과 달라진다
- 이름을 믿고 다른 데를 찾게 되므로 시간이 든다
- 무엇이 들어 있는지 세어 보면 실제 용도가 드러난다
- 코드만으로는 그 비율을 알 수 없고 세어 봐야 나온다
- 나눌지 합칠지는 공통 로직이 얼마나 되는지로 정한다
- 유형 컬럼을 넣을 때 겹치는 행이 있는지 먼저 확인한다
- 이름은 별칭을 두고 천천히 바꾸고 옛 이름이 사라진 뒤에 별칭을 지운다
- 주석에는 경위 대신 지금 무엇인지만 적는다
- 같은 상황을 찾으려면 테이블 이름의 개념과 컬럼을 대조한다