알림을 종류별로 다른 대상에 보내는 봇에서 대상이 바뀌어 설정을 고쳐야 했다. 라우팅이 어디서 정해지는지 찾다가 상수 배열에 닿았다.
Table of contents
Open Table of contents
상수에 들어 있던 라우팅
구독 테이블이 있고 거기서 라우팅이 결정되는 구조였다. 그런데 그 테이블을 채우는 초기 데이터 상수가 코드에 따로 있었다.
종류별 대상 식별자가 그 배열에 그대로 적혀 있었으므로 사실상 그것이 라우팅 정의였다. 테이블은 그 배열의 사본에 가까웠다.
조건부 삽입이 증상을 감춘다
삽입이 조건부라서 이미 행이 있으면 아무것도 하지 않는다. 운영 중인 서버는 데이터베이스가 이미 있으니 상수가 낡아도 아무 일이 일어나지 않는다.
반대로 데이터베이스를 새로 만드는 환경에서는 그 상수가 라우팅을 결정한다. 낡은 채로 오래 있다가 재생성 시점에 죽은 대상으로 조용히 되돌아가는 구조다.
식별자가 바뀌는 두 경로
식별자가 왜 바뀌는지 보니 경로가 둘이었다. 대상 자체를 교체한 경우는 명확하지만 승격에 의한 무효화는 예상 밖이었다.
그룹이 일정 규모를 넘으면 자동으로 승격되고 옛 식별자가 영구 무효가 된다. 우리가 아무것도 안 해도 값이 바뀌는데 실패 응답의 본문에 새 값이 담겨 오므로 그 응답을 안 보면 전송 실패로만 보인다.
옛 값을 남기지 않은 이유
상수를 고치면서 옛 값을 주석으로 남길지 판단해야 했다. 남기지 않기로 한 것은 조건부 삽입 때문이었다.
옛 값을 배열에 남겨 두면 새 데이터베이스에 아무 데도 가지 않는 구독 행이 하나 더 생긴다. 이력이 필요하면 버전 관리에 있으므로 상수에는 현재 유효한 것만 둔다.
사고 이력이 아니라 규칙으로
원래 그 상수 위에는 날짜와 함께 무슨 일이 있었는지가 적혀 있었다. 읽으면 사정은 알겠는데 지금 무엇을 해야 하는지는 알려 주지 않는 주석이었다.
대상이 바뀌면 교체든 승격이든 이 목록을 현재 값으로 갈아 끼우고 옛 값은 남기지 않는다는 문장으로 바꿨다. 주석 이력을 보니 이 상수는 여러 번 갱신 대상이 됐으므로 일회성 경위가 아니라 반복 적용될 규칙이 필요했다.
정리
- 초기 데이터 상수가 사실상 설정 정의가 되는 경우가 있다
- 조건부 삽입이면 상수가 낡아도 증상이 안 보인다
- 재생성 시점에 죽은 값으로 조용히 되돌아간다
- 식별자는 우리가 안 바꿔도 외부 요인으로 바뀔 수 있다
- 실패 응답 본문에 새 값이 담겨 오는 경우가 있다
- 조건부 삽입 목록에 옛 값을 남기면 죽은 행이 쌓인다
- 이력은 버전 관리에 있으므로 상수에는 유효한 것만 둔다
- 주석은 사고 이력이 아니라 다음 사람이 실행할 규칙으로 쓴다