버그 수정 릴리스 노트, 쓸모 있는 항목을 쓰는 법
5분 분량
좋은 버그 수정 릴리스 노트는 코드가 무엇을 잘못했는지가 아니라 사용자가 무엇이 잘못되는 것을 보았는지를 설명한다. 각 항목은 누가 영향을 받았는지, 언제부터였는지, 수정이 완전한지, 그리고 독자가 해야 할 일이 있는지를 밝힌다. 그 일이 “조치가 필요 없음”뿐이라도 마찬가지다.
대부분의 팀은 커밋 메시지에서 한 줄을 그대로 가져온다. 아래 표는 여섯 가지 고쳐 쓰기를 보여주고, 이어지는 절들은 그 규칙을 설명한다.
| 이전 (커밋 메시지) | 이후 (증상) |
|---|---|
| Fixed null pointer in export handler | 태그가 없는 프로젝트에서 내보내기가 더 이상 “문제가 발생했습니다”로 실패하지 않습니다. 9월 3일 이후 실패한 내보내기는 다시 실행하세요. |
| Resolved race condition in sync worker | 두 기기에서 몇 초 안에 한 편집이 더 이상 서로를 덮어쓰지 않습니다. 할 일은 없습니다. |
| Fix timezone bug | 예약된 보고서가 이제 설정한 시간에 실행됩니다. UTC보다 동쪽에 있는 계정은 8월 12일부터 보고서가 최대 하루 일찍 실행되었습니다. 변경할 필요는 없습니다. |
| Patched XSS in comment renderer | 보안 수정: 조작된 댓글이 다른 사용자의 브라우저에서 스크립트를 실행할 수 있었습니다. 오늘 4.2.1로 업그레이드하세요. 로그에서 악용된 정황은 발견하지 못했습니다. |
| Fixed regression from 4.1.0 | 하이픈이 들어간 검색어도 다시 검색됩니다. 4.1.0에서 고장 났고 4.1.1에서 수정되었습니다. |
| Bug fixes and performance improvements | 어떤 것인지 말하세요. 마지막 절을 보세요. |
릴리스 노트에 버그 수정 항목은 어떻게 쓰는가
사용자의 말로 된 증상으로 시작하고, 그다음 누가 언제부터 영향을 받았는지, 수정의 상태, 그리고 조치 순으로 쓴다. 보통 한두 문장이면 충분하다. 코드상의 원인은 엔지니어가 찾아볼 pull request에 두면 된다.
독자는 한 가지를 보고 훑는다. “이게 나였나?” 네 부분이면 거의 모든 항목을 다룬다.
- 증상. 화면, API 응답, 청구서에 무엇이 나타났는가. 오류 문구가 있었다면 그대로 인용하라. 사람들이 그 문구로 검색하기 때문이다.
- 범위. 어떤 요금제, 플랫폼, API 버전, 데이터 형태인가. “행이 5만 개가 넘는 계정”은 확인할 수 있지만, “일부 사용자”는 확인할 수 없다.
- 기간. 어느 릴리스나 날짜부터인가. 어제의 이상한 결과가 그 버그 때문이었는지 독자가 판단할 수 있도록 한다.
- 조치. 다시 실행, 다시 동기화, 업그레이드, 임시방편 제거, 또는 아무것도 하지 않음.
사용자가 임시방편을 만들어 두었다면, 이제 지워도 된다고 알려주는 자리가 조치 줄이다.
릴리스 노트와 체인지로그의 차이는 무엇인가
체인지로그는 변경의 완전하고 계속 이어지는 기록이다. 릴리스 노트는 관심을 가질지 판단하려는 사람들을 위해, 하나의 릴리스에 대해 골라서 다시 쓴 메시지다. 버그 수정의 경우 체인지로그는 모든 수정을 나열하고, 노트는 독자가 알아챘을 법한 것들을 앞세운다.
툴팁의 오타는 체인지로그에만 속한다. 청구서의 잘못된 세율은 둘 다에 속한다. 전체 구분은 체인지로그 대 릴리스 노트에 있고, 좋은 노트 묶음의 형태는 릴리스 노트를 쓰는 방법에 있다.
Keep a Changelog는 기록 쪽에서 쓰기 편한 관례다. 버그 수정에는 “Fixed”를, 취약점에는 별도의 “Security” 제목을 두는데, 이 글이 독자를 위해 나누는 구분과 같다.
버그 수정도 업데이트인가
그렇다. 버그 수정은 제품을 바꾸므로, 수정을 내보내는 것은 업데이트다. 시맨틱 버저닝에서 하위 호환되는 수정은 패치 릴리스이며, 예를 들어 4.2.0에서 4.2.1이 된다.
독자가 무언가를 해야 하는지는 별개의 질문이며, 노트가 그것에 답해야 한다. 올바르게 호출하는 쪽이 관찰하는 결과를 바꾸는 수정은 파괴적 변경에 가깝고, 그 경계가 어디인지는 파괴적 변경에서 설명한다.
수정은 언제 독자적인 항목이 되고, 언제 사소한 수정인가
사용자가 그 버그를 알아챘을 수 있거나, 그 때문에 시간이나 데이터를 잃었거나, 임시방편을 만들었다면 독자적인 항목을 준다. 팀 밖의 누구도 볼 수 없었다면 짧은 “사소한 수정” 목록으로 묶는다. diff의 크기와 상관없이, 독자의 경험을 기준으로 판단하라.
| 독자적인 항목이 되는 경우 | 사소한 수정 목록에 들어가는 경우 |
|---|---|
| 고객이 신고했거나 많은 사람이 겪은 것 | 거의 열리지 않는 화면의 외관상 결함 |
| 잘못된 출력, 실패한 작업, 날아간 작업을 일으킨 것 | 오타, 간격, 어긋난 아이콘 |
| 독자의 조치가 필요한 것 | 내부 도구나 관리자 페이지의 수정 |
| 최근 릴리스에서 생긴 회귀 | 테스트 환경에서만 보인 실패 |
| 결제, 권한, 데이터와 관련된 것 | 로그 문구, 사용자 영향이 없는 의존성 업데이트 |
묶음 속의 각 줄도 무언가를 말해야 한다. “일부 UI 문제를 수정했습니다”는 자리표시자일 뿐이다.
회귀는 어떻게 쓰는가
그것을 만든 릴리스를 밝히고, 회귀라고 부르고, 그것을 고치는 릴리스를 알려라. 그 버그를 겪은 사람은 이미 고장 났다는 것을 알고 있으므로, 짧고 직접적인 인정이 모호한 표현보다 그들에게 도움이 된다.
예를 들면 이렇다. “하이픈이 들어간 검색어의 검색 결과가 4.1.0에서 비어서 나왔습니다. 4.1.1에서 수정되었습니다. 하이픈을 피하려고 검색어를 바꾸셨다면 다시 되돌리셔도 됩니다.”
“검색 안정성을 개선했습니다”는 그 버그 때문에 오후 한나절을 잃은 사람에게는 얼버무리는 것처럼 읽힌다. 원인을 아직 확인하는 중이라면 그렇다고 말하라. 긴급 릴리스 노트의 지침대로, 노트가 팀이 아는 것보다 더 확신에 차게 들리면 안 된다.
보안 수정은 어떻게 공지하는가
심각도를 분명하게 밝히고, 영향받는 버전과 이를 고친 버전을 적고, 업그레이드가 얼마나 급한지 알리고, CVE 식별자가 있다면 포함하라. 사용자가 수정을 적용할 수 있게 된 뒤에만 세부 사항을 공개하며, 신고자가 있었다면 조율된 공개 절차를 따른다.
순서가 중요하다. 신고자가 비공개로 알려주고, 수정을 출시하고, 사용자가 스스로를 보호할 수 있게 되었을 때 공개 노트를 내보낸다. CISA의 조율된 취약점 공개 절차는 취약점의 신고, 분석, 공개를 조율한다. CVE Numbering Authority 규칙은 CVE 레코드가 어떻게 부여되고 게시되는지를 규정하며, GitHub에서는 저장소 보안 권고로 권고문을 비공개로 작성하고 식별자를 요청할 수 있다.
보안 항목에는 보통 네 가지 사실이 담긴다.
- 공격자가 무엇을 할 수 있었는지. 한 문장으로, 개념 증명 없이.
- 영향받는 버전과 이를 고친 버전.
- 얼마나 급한지. “오늘 업그레이드” 또는 “다음 릴리스 때 업그레이드”.
- 악용을 확인했는지, 그리고 신고자가 동의했다면 신고자에 대한 감사.
악용 절차는 빼라.
데이터 손실 수정에 대해 노트는 무엇을 말해야 하는가
어떤 데이터가 영향을 받았는지, 내 것이 해당되는지 어떻게 알 수 있는지, 복구할 수 있는지를 말하라. 여기서 “조치가 필요 없음”이 맞는 경우는 드물고, 독자의 첫 질문은 “내 데이터가 사라졌나”이다.
쓸 만한 항목은 데이터를 잃게 만든 조건(“동기화가 실행되는 동안 폴더를 삭제함”), 그것이 가능했던 기간, 확인 방법(“휴지통을 열어 9월 3일부터 9일 사이의 항목을 찾아보세요”), 그리고 복구 경로를 제시한다. 데이터를 복구할 수 없다면 그렇게 말하라. 영향받은 고객에게는 직접 연락도 하라. 자신의 데이터가 피해를 입었다는 사실을 알게 되는 곳이 릴리스 노트뿐이어서는 안 되기 때문이다.
“버그 수정 및 성능 개선”이 나쁜 노트인 이유는 무엇인가
독자가 행동할 거리를 전혀 주지 않고, 누군가 기다리던 수정을 숨긴다. 충돌을 신고한 고객은 그것이 고쳐졌는지 알 수 없고, 임시방편을 쓰는 고객은 그것을 제거해야 하는지 알 수 없다.
정직한 대안은 두 가지다. 릴리스에 독자가 알아챌 만한 것이 없다면 노트를 발행하지 않고 기록은 체인지로그에 맡겨라. 수정이 있다면 독자의 언어로 나열하라.
이전:
버그 수정 및 성능 개선.
이후:
수정: 태그 없는 프로젝트에서 CSV 내보내기가 실패함.
수정: 다크 모드에서 댓글 입력창의 커서가 안 보임.
속도: 프로젝트가 100개 넘는 워크스페이스에서
대시보드가 더 빨리 열림.
버그 수정 노트는 어디에서 오는가
버그를 고친 pull request와 그 계기가 된 신고에서 온다. 신고자의 말이 수정과 함께 전해진다면, 증상의 절반은 이미 쓰인 셈이다.
기능 요청과 버그 리포트의 구분은 신고를 올바르게 분류하는 일이 왜 담당을 결정하는지 설명한다. Changeloop에서는 위젯으로 신고된 버그가 bug 라벨이 붙은 GitHub issue가 되고, 체인지로그 항목은 병합된 pull request에서 초안이 작성되어 발행되기 전에 사람이 승인하도록 보류된다. 릴리스 노트 템플릿은 직접 쓸 때를 위해 같은 항목 형태를 제공한다. 증상, 범위, 기간, 조치다.
FAQ
버그 수정 릴리스 노트에는 무엇이 들어가야 하는가? 각 항목은 사용자가 본 증상, 영향받은 대상, 어느 릴리스나 날짜부터인지, 수정이 완전한지, 그리고 “아무것도 없음”을 포함해 독자가 해야 할 일을 밝혀야 한다.
모든 버그 수정을 릴리스 노트에 나열해야 하는가? 아니다. 사용자가 알아챘거나, 시간을 잃었거나, 우회한 것만 나열하고, 외관상이거나 내부적인 수정은 짧은 “사소한 수정” 목록으로 묶어라. 체인지로그는 찾아봐야 하는 누구를 위해서든 모든 수정을 보관한다.
내가 만든 버그에 대한 릴리스 노트는 어떻게 쓰는가? 회귀였다고 말하고, 그것을 만든 릴리스와 고친 릴리스를 밝히고, 독자가 임시방편을 지워도 되는지 알려라. 완곡하게 돌려 말한 표현보다 담백한 서술이 더 낫게 읽힌다.
사용 중인 제품의 릴리스 노트는 어떻게 확인하는가? 제품의 도움말 메뉴, 푸터, 문서에 링크된 체인지로그나 릴리스 노트 페이지를 찾아보라. 오픈 소스 프로젝트라면 저장소의 releases 탭을 보면 된다.
이 글의 기술적 내용은 독립적으로 검토되지 않았습니다. 잘못된 부분이 있으면 알려 주세요. 바로잡겠습니다.