결제 연동에 쓰는 상점 계정 mid 를 바꿔 달라는 요청이 왔다. config 의 설정 파일에서 바꿨는데 안 바뀐다.
Table of contents
Open Table of contents
정해지는 자리가 여럿이었다
값이 어디서 오는지 따라갔다.
// 1. 결제 요청
$mid = $this->payment->getMid();
// 2. Payment 라이브러리
public function getMid() {
return $this->client->mid;
}
// 3. 클라이언트 객체 생성
$this->client = PaymentClientFactory::create($channel);
// 4. 팩토리
public static function create($channel) {
$row = $this->db->where('channel', $channel)->get('payment_client')->row();
return new PaymentClient($row->mid, $row->key);
}
설정 파일이 아니라 payment_client 테이블에서 온다. 설정 파일에도 같은 이름의 값이 있었는데 그것은 예전에 쓰던 것이고 지금은 아무도 안 읽는다.
값이 정해질 수 있는 자리가 config 와 payment_client 와 코드 기본값으로 여럿이고 앞의 것이 없으면 다음으로 넘어간다. 어느 계층에서 정해지는지를 모르면 고칠 자리 자체를 못 찾는다.
체인을 그려 봤다
값이 정해지는 경로를 그려 봤다.
결제 요청
→ Payment 라이브러리
→ PaymentClientFactory
→ payment_client 테이블 (channel 로 조회)
바꿀 자리는 payment_client 다. 이 그림이 없으면 config 부터 뒤진다.
왜 테이블로 갔는지도 확인했다. channel 이 여럿이고 각각 다른 mid 를 쓰며 운영 중에 바뀌는데 설정 파일이면 채널이 늘 때마다 배포가 필요하다.
이유를 알고 나니 config 의 옛 값을 지워도 되는지가 정해져서 지웠다. 안 읽히는 값이 남아 있으면 다음 사람이 나와 똑같이 그것을 고치고 안 바뀐다고 할 것이다.
어느 채널인지도 봐야 했다
테이블에 행이 여럿이다.
SELECT channel, mid, use_yn FROM payment_client;
channel mid use_yn
card M1234567 Y
mobile M1234568 Y
card M9999999 N
card 가 두 행이고 하나는 안 쓰는 것이다. create 가 use_yn 조건을 안 걸고 있었다.
$row = $this->db->where('channel', $channel)->get('payment_client')->row();
row() 가 어느 행을 가져올지는 정렬에 달렸는데 정렬이 없으면 예측이 안 된다. 매뉴얼도 정렬 컬럼의 값이 같으면 서버가 어느 순서로든 돌려줄 수 있고 실행 계획에 따라 달라진다고 적고 있다.
조건과 정렬을 넣었다.
$row = $this->db->where('channel', $channel)
->where('use_yn', 'Y')
->order_by('client_no', 'desc')
->get('payment_client')->row();
조건 없는 단건 조회는 어느 행이 올지 모른다. 정렬만 붙여서도 부족한데 같은 채널의 행이 둘이면 정렬 값이 같아져 다시 미정으로 돌아가므로 기본키를 정렬에 하나 더 얹어야 확정된다.
안 쓰는 행과 바꾸는 순서
use_yn='N' 행을 지울지 남길지 봤다. 남기기로 했는데 옛 결제 건의 mid 를 조회할 일이 있고 지우면 그 이력을 못 읽는다.
대신 조회할 때 조건을 반드시 걸게 하고 조회를 한 곳으로 모았다.
class PaymentClientRepository {
public function getActive($channel) { ... } // use_yn='Y'
public function getById($no) { ... } // 이력 조회용
}
getActive 와 getById 로 이름에서 용도가 갈린다.
계정을 바꾸는 일이 또 있을 것이라 절차도 적었다.
1. 새 행을 추가한다 (use_yn='N' 으로)
2. 시험 환경에서 그 행을 활성으로 바꿔 시험한다
3. 정상이면 운영에서 옛 행을 'N', 새 행을 'Y' 로
4. 결제 한 건을 실제로 해 본다
5. 문제가 있으면 3번을 되돌린다
행을 지우고 새로 만드는 대신 추가하고 전환한다. 되돌리기가 한 줄이다.
검증 — 체인에 낀 캐시
바꾸고 나서도 옛 mid 가 나왔다. getActive 의 조회 결과를 캐시하고 있었다.
$row = $this->cache->get("payment_client:{$channel}");
if (!$row) {
$row = $this->repo->getActive($channel);
$this->cache->save("payment_client:{$channel}", $row, 3600);
}
3600 이라 한 시간이고 바꾸면 최대 한 시간 뒤에 반영된다.
$this->cache->delete("payment_client:{$channel}");
바꾸는 화면에서 캐시를 지우게 했다. 값이 정해지는 체인에 캐시가 끼어 있으면 그것도 체인의 일부다.
정리
- 값이 어느 계층에서 정해지는지 모르면 바꿀 자리를 못 찾는다
- 경로를 따라가 그려 보면 어디를 고칠지가 정해진다
- 설정 파일에 안 읽히는 옛 값이 남아 있을 수 있으니 확인하고 지운다
- 조건 없는 단건 조회는 어느 행이 올지 예측이 안 된다
- 정렬 값이 동점이면 여전히 미정이라 기본키를 하나 더 얹는다
- 안 쓰는 행을 남길지는 이력 조회가 필요한지로 정한다
- 조회를 한 곳으로 모으고 이름으로 용도를 가른다
- 바꿀 때는 지우고 새로 만들지 말고 추가하고 전환한다
- 캐시가 끼어 있으면 그것도 체인의 일부라 바꿀 때 같이 지운다