쓰던 라이브러리가 어떤 조건에서 값을 잘못 돌려줘서 그 조건을 피해 가는 우회 코드를 만들었다.
만들고 나서 그 문제가 다음 판에서 고쳐졌다는 것을 알았다.
Table of contents
Open Table of contents
우리 문제인지부터 갈랐다
증상을 보고 처음에는 우리 코드를 뒤졌다. 파싱 결과가 이상한데 넘기는 값은 맞았다. 그 사이 어디가 틀어졌는지를 찾느라 반나절을 썼다. 그러다 SomeLib 쪽이라는 것을 알았다.
가르는 방법은 최소 재현이었다.
// 우리 코드 없이 라이브러리만 부른다
$r = SomeLib::parse("2017-03-12T00:00:00+09:00");
var_dump($r); // 기대와 다른 값
우리 코드를 다 걷어 내고 SomeLib::parse 만 부르는데도 같은 값이 나오면 라이브러리 문제다.
var_dump 두 줄짜리 최소 재현을 만들면 어느 쪽 문제인지가 그 자리에서 갈린다. 그리고 이 몇 줄은 뒤의 모든 단계에서 다시 쓰인다.
고쳐진 판이 있는지 봤다
SomeLib 문제로 확정하고 나서 볼 것이 셋이었다.
1. 우리가 쓰는 판이 몇 판인가
2. 최신 판이 몇 판인가
3. 그 사이에 이 문제가 고쳐졌나
변경 내역을 훑으니 두 판 뒤에 같은 증상이 고쳐져 있었다.
v2.4.1
- Fix timezone offset parsing for +09:00 format
우리는 2.3.8 을 쓰고 있었고 2.4.1 에 Fix timezone offset parsing 이 들어 있었다. 우리가 겪는 문제는 대개 다른 사람도 겪었고 그러면 이미 고쳐져 있다.
CHANGELOG 를 훑는 데 몇 분이면 되는데 그것을 우회를 다 만든 뒤에 한 것이 이번의 문제였다.
판단 기준 — 올릴 수 있는지
고쳐진 판이 있어도 바로 올릴 수 있는 것은 아니라서 셋을 나눠 봤다.
호환성으로는 2.3 에서 2.4 로 가면서 바뀐 것을 봤는데 함수 하나의 인자 순서가 바뀌어 있었다. 의존성으로는 다른 것이 SomeLib 의 특정 판을 요구하는지 봤다.
세 번째는 우리 코드에서 이것을 부르는 곳의 수였다. 세어 보니 14군데였고 그중 인자 순서가 바뀐 함수를 쓰는 곳은 2군데였다.
14군데 전부를 고쳐야 했으면 판단이 달랐을 텐데 2군데면 고칠 만해서 올리는 쪽으로 정했다.
올리고 확인했다
시험 환경에서 먼저 올리고 네 단계를 밟았다.
1. 판을 올린다
2. 최소 재현을 돌려 문제가 없어졌는지 본다
3. 그 라이브러리를 쓰는 14곳을 확인한다
4. 전체 시험을 돌린다
둘째가 핵심이었다. 아까 만든 SomeLib::parse 최소 재현을 그대로 다시 돌려 값이 바뀌었는지를 본다.
이것이 없으면 판만 올리고 문제는 그대로일 수 있으니 올린 이유가 성립하는지를 그 몇 줄이 확인해 준다.
못 올리는 경우도 있었다
다른 건에서는 판을 못 올렸는데 최신 판이 우리가 쓰는 PHP 5.6 을 지원하지 않았다.
그때는 우회를 만들되 기록을 남겼다.
/**
* SomeLib 2.3.8 의 파싱 결함 우회.
* 2.4.1 에서 수정됐으나 PHP 5.6 미지원으로 올리지 못함.
* PHP 7 이행 시 이 함수를 제거하고 SomeLib::parse 를 직접 쓸 것.
*/
function parseDateSafe($s) { ... }
parseDateSafe 를 언제 지울 수 있는지를 조건으로 적었다. 조건이 없으면 이 함수는 영원히 남고 몇 해 뒤에는 왜 있는지도 모르게 된다.
참고 자료 — 우회 목록
이런 우회가 여럿 생겨서 따로 모았다.
docs/workarounds.md
| 대상 | 판 | 문제 | 해소 조건 |
|---|---|---|---|
| SomeLib | 2.3.8 | 시간대 파싱 | PHP 7 이행 후 2.4.1 로 |
| OtherLib | 1.2.0 | 인코딩 | 1.3 에서 수정, 의존성 확인 필요 |
workarounds.md 에 대상과 판과 해소 조건을 적어 두고 PHP 7 이행 같은 일이 생기면 이 목록을 함께 연다.
주석만 있으면 그 파일을 열어야 보이는데 목록으로 모아 두면 이행 작업의 할 일이 된다. 우회를 지우는 시점이 그렇게 정해진다.
전체 흐름 — 확인 순서
라이브러리 문제로 보일 때 볼 순서를 정했다.
1. 최소 재현으로 우리 문제인지 가른다
2. 우리가 쓰는 판과 최신 판을 확인한다
3. 변경 내역에서 관련 수정이 있는지 본다
4. 있으면 올릴 수 있는지 확인한다 (호환성·의존성·쓰는 곳 수)
5. 못 올리면 우회를 만들고 해소 조건을 적는다
6. 고쳐진 적 없으면 보고를 검토한다
첫째부터 셋째까지가 십 분이면 끝난다. 우회를 만드는 것보다 훨씬 짧은데 이번에는 그 십 분을 건너뛰었다.
여섯째도 실제로 써먹었다. 고쳐진 적 없는 건을 보고했더니 다음 판에서 고쳐졌고 그때도 최소 재현이 쓰였다.
정리
- 도구 문제로 보이면 최소 재현으로 어느 쪽 문제인지 먼저 가른다
- 최소 재현은 확인과 보고에서 계속 다시 쓰인다
- 도구 문제면 변경 내역에서 고쳐진 판이 있는지 본다
- 만들기 전에 확인하는 것과 만들고 나서 하는 것이 다르다
- 올릴 수 있는지는 호환성과 의존성과 쓰는 곳 수로 판단한다
- 올린 뒤 최소 재현을 다시 돌려 값이 바뀌었는지 확인한다
- 못 올리면 우회를 만들되 언제 지울 수 있는지를 조건으로 적는다
- 우회를
workarounds.md에 모아 두고 이행할 때 함께 본다 - 고쳐진 적 없으면 최소 재현을 붙여 보고한다