BTC 마켓을 붙이는 중이었다. 유동성 공급사의 페어 스펙(호가 단위·최소 주문 수량) 마스터가 오래돼서 갱신해야 했다. 배치 스크립트가 있을 것 같아 찾았다.
Table of contents
Open Table of contents
상황 — 갱신할 스크립트를 찾았다
scripts/ 아래를 훑었다.
ls scripts/
하나가 눈에 띄었다.
sync_markets.php
sync_markets.php 라는 이름만 보면 마켓 목록을 맞추는 것으로 읽힌다.
이대로 돌리면 끝날 일로 보였고 이름이 맞으니 안을 안 열어 보고 실행할 뻔했다.
원인 — 이름이 맞아 보이던 것
열어 보니 다루는 대상이 달랐다.
// scripts/sync_markets.php
// 마켓 메이커 봇의 마켓 캐시만 갱신한다
$bot->reloadMarketCache($this->markets->all());
sync_markets.php 는 우리가 갱신하려는 페어 스펙 마스터가 아니라 마켓 메이커 봇의 캐시 전용이었다.
그대로 돌렸으면 봇 캐시를 옛 마스터로 다시 채울 뻔했다. 이름이 맞을수록 안을 안 보게 되니 위험이 더 컸다.
전수로 찾으니 없었다
다른 것이 있는지 스크립트 머리말을 전부 훑었다.
grep -ln "pair\|market" scripts/*.php | xargs head -3
머리말을 전부 뽑아 봐도 페어 스펙을 갱신하는 스크립트가 아예 없었다.
없는 것을 이름으로 찾고 있었던 셈이라 애초에 나올 리가 없었고 전수로 훑고 나서야 그 사실이 확정됐다.
스크립트가 없으면 다른 경로가 있을 것으로 보고 routes.php 를 봤다.
grep -n "market" routes.php
관리 API 쪽 라우트에서 하나가 나왔다.
GET /admin/api/markets/get-lp-markets?lp=...
get-lp-markets 는 이름만 보면 조회로 읽혀서 이것이 맞는지 확신할 수 없었다.
조치 — 반드시 거치는 지점에서 역추적
이름을 근거로 삼는 검색은 그 이름이 정확할 때만 작동한다.
[이름으로 찾기] 이름이 맞아야 찾아짐
[필수 지점에서 역추적] 이름과 무관
이름으로 계속 찾는 대신 다른 방법인 역추적 쪽을 골랐다. 이유는 페어 스펙을 받으려면 공급사 클라이언트의 그 함수를 안 거칠 수 없어서다.
① 공급사 클라이언트에서 페어 스펙을 받는 함수를 찾음
getPairSpecsReq()
② 그 함수를 호출하는 곳을 찾음
grep -rn "getPairSpecsReq" application/
③ 컨트롤러에 도달
페어 스펙을 받으려면 getPairSpecsReq 를 안 거칠 수 없다.
이름이 무엇이든 그 자리를 지나야 하므로 grep 으로 호출자를 찾아 올라가면 경로가 잡힌다. 외부 호출이 그런 지점이 되는 경우가 많았다.
주의 — 조회처럼 보이던 이름
역추적으로 닿은 컨트롤러를 열어 봤다.
public function getLpMarkets(array $query)
{
$lp = $this->lpClients->get($query['lp']);
$specs = $lp->getPairSpecsReq();
$this->markets->replaceSpecs($specs); // 마스터 테이블 갱신
}
getLpMarkets 는 공급사에서 받아 우리 표를 갱신하는 동작이었다.
[이름] get-lp-markets — 가져오기
[동작] 가져와서 저장
get 으로 시작하는데 쓰기 동작이다.
이름과 동작이 어긋나 있으니 이름으로 찾아서는 영영 못 찾는 것이 당연했다. 앞의 스크립트와 이쪽이 서로 반대 방향으로 어긋나 있어서 두 번 헷갈린 셈이다.
비교 — 혼동하기 쉬운 이웃
같은 영역에 비슷한 것이 하나 더 있었다.
POST /admin/markets/update
markets/update 가 오히려 갱신처럼 보이는데 실제로는 마켓 노출 설정 수정이었다.
[노출 설정 수정] 활성 여부·표시 순서·공지 문구
[마스터 동기화] 호가 단위·최소 수량 자체를 공급사에서 받아옴
노출 설정 수정 과 마스터 동기화 는 하는 일이 다르다.
혼동해서 markets/update 를 부르면 노출 설정만 바뀌고 스펙은 그대로 남는다. HTTP 오류는 안 난다. 갱신했는데 여전히 옛 호가 단위로 주문이 거절되는 상태가 된다.
그래서 기록에 get-lp-markets 와 markets/update 를 같이 적었다. 맞는 것만 적으면 다음 사람이 또 헷갈리므로 틀리기 쉬운 것을 나란히 적어 두는 편이 낫다.
scripts/ 에 해당 스크립트가 없는 것 자체도 남겨 뒀다. 사람이 눌러야 도는 구조라 아무도 안 누르면 계속 낡고 이번에 찾은 것도 그래서였다.
정리
- 이름이 맞아 보이는 스크립트가 다른 대상 전용이었다
- 이름이 맞을수록 안을 안 보게 되니 위험이 더 크다
- 전수로 찾고 나서야 없다는 것이 확정된다
- 이름으로 못 찾으면 반드시 거치는 지점에서 역추적한다
- 외부 호출 함수가 그런 지점이 된다
- 이름이 조회처럼 보이는데 갱신인 경우가 있다
- 이름 기반 검색은 이름이 정확할 때만 작동한다
- 이름이 비슷한 이웃을 잘못 부르면 아무 일도 안 일어난 것처럼 보인다
- 오류가 안 나므로 갱신됐다고 믿고 넘어간다
- 기록에 맞는 것과 틀리기 쉬운 것을 같이 적는다
- 사람이 눌러야 도는 구조는 아무도 안 누르면 계속 낡는다