<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>changeloop blog</title><description>실전 릴리스 노트, 그리고 빌드 산출물로서의 changelog.</description><link>https://changeloop.dev/</link><language>ko-KR</language><item><title>버그 수정 릴리스 노트, 쓸모 있는 항목을 쓰는 법</title><link>https://changeloop.dev/blog/ko/bug-fix-release-notes/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/bug-fix-release-notes/</guid><description>버그 수정 릴리스 노트는 항목마다 증상, 영향받은 대상, 다음에 할 일을 밝혀야 읽힌다. 전후 사례와 보안 수정, 데이터 손실 수정 규칙을 정리했다.</description><pubDate>Fri, 02 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;좋은 버그 수정 릴리스 노트는 코드가 무엇을 잘못했는지가 아니라 사용자가 무엇이 잘못되는 것을 보았는지를 설명한다. 각 항목은 누가 영향을 받았는지, 언제부터였는지, 수정이 완전한지, 그리고 독자가 해야 할 일이 있는지를 밝힌다. 그 일이 &amp;quot;조치가 필요 없음&amp;quot;뿐이라도 마찬가지다.&lt;/p&gt;
&lt;p&gt;대부분의 팀은 커밋 메시지에서 한 줄을 그대로 가져온다. 아래 표는 여섯 가지 고쳐 쓰기를 보여주고, 이어지는 절들은 그 규칙을 설명한다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;이전 (커밋 메시지)&lt;/th&gt;
&lt;th&gt;이후 (증상)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Fixed null pointer in export handler&lt;/td&gt;
&lt;td&gt;태그가 없는 프로젝트에서 내보내기가 더 이상 &amp;quot;문제가 발생했습니다&amp;quot;로 실패하지 않습니다. 9월 3일 이후 실패한 내보내기는 다시 실행하세요.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resolved race condition in sync worker&lt;/td&gt;
&lt;td&gt;두 기기에서 몇 초 안에 한 편집이 더 이상 서로를 덮어쓰지 않습니다. 할 일은 없습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fix timezone bug&lt;/td&gt;
&lt;td&gt;예약된 보고서가 이제 설정한 시간에 실행됩니다. UTC보다 동쪽에 있는 계정은 8월 12일부터 보고서가 최대 하루 일찍 실행되었습니다. 변경할 필요는 없습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Patched XSS in comment renderer&lt;/td&gt;
&lt;td&gt;보안 수정: 조작된 댓글이 다른 사용자의 브라우저에서 스크립트를 실행할 수 있었습니다. 오늘 4.2.1로 업그레이드하세요. 로그에서 악용된 정황은 발견하지 못했습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fixed regression from 4.1.0&lt;/td&gt;
&lt;td&gt;하이픈이 들어간 검색어도 다시 검색됩니다. 4.1.0에서 고장 났고 4.1.1에서 수정되었습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bug fixes and performance improvements&lt;/td&gt;
&lt;td&gt;어떤 것인지 말하세요. 마지막 절을 보세요.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;릴리스 노트에 버그 수정 항목은 어떻게 쓰는가&lt;/h2&gt;
&lt;p&gt;사용자의 말로 된 증상으로 시작하고, 그다음 누가 언제부터 영향을 받았는지, 수정의 상태, 그리고 조치 순으로 쓴다. 보통 한두 문장이면 충분하다. 코드상의 원인은 엔지니어가 찾아볼 pull request에 두면 된다.&lt;/p&gt;
&lt;p&gt;독자는 한 가지를 보고 훑는다. &amp;quot;이게 나였나?&amp;quot; 네 부분이면 거의 모든 항목을 다룬다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;증상.&lt;/strong&gt; 화면, API 응답, 청구서에 무엇이 나타났는가. 오류 문구가 있었다면 그대로 인용하라. 사람들이 그 문구로 검색하기 때문이다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;범위.&lt;/strong&gt; 어떤 요금제, 플랫폼, API 버전, 데이터 형태인가. &amp;quot;행이 5만 개가 넘는 계정&amp;quot;은 확인할 수 있지만, &amp;quot;일부 사용자&amp;quot;는 확인할 수 없다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;기간.&lt;/strong&gt; 어느 릴리스나 날짜부터인가. 어제의 이상한 결과가 그 버그 때문이었는지 독자가 판단할 수 있도록 한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;조치.&lt;/strong&gt; 다시 실행, 다시 동기화, 업그레이드, 임시방편 제거, 또는 아무것도 하지 않음.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;사용자가 임시방편을 만들어 두었다면, 이제 지워도 된다고 알려주는 자리가 조치 줄이다.&lt;/p&gt;
&lt;h2&gt;릴리스 노트와 체인지로그의 차이는 무엇인가&lt;/h2&gt;
&lt;p&gt;체인지로그는 변경의 완전하고 계속 이어지는 기록이다. 릴리스 노트는 관심을 가질지 판단하려는 사람들을 위해, 하나의 릴리스에 대해 골라서 다시 쓴 메시지다. 버그 수정의 경우 체인지로그는 모든 수정을 나열하고, 노트는 독자가 알아챘을 법한 것들을 앞세운다.&lt;/p&gt;
&lt;p&gt;툴팁의 오타는 체인지로그에만 속한다. 청구서의 잘못된 세율은 둘 다에 속한다. 전체 구분은 &lt;a href=&quot;https://changeloop.dev/blog/ko/changelog-vs-release-notes/&quot;&gt;체인지로그 대 릴리스 노트&lt;/a&gt;에 있고, 좋은 노트 묶음의 형태는 &lt;a href=&quot;https://changeloop.dev/blog/ko/how-to-write-release-notes/&quot;&gt;릴리스 노트를 쓰는 방법&lt;/a&gt;에 있다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://keepachangelog.com/en/1.1.0/&quot;&gt;Keep a Changelog&lt;/a&gt;는 기록 쪽에서 쓰기 편한 관례다. 버그 수정에는 &amp;quot;Fixed&amp;quot;를, 취약점에는 별도의 &amp;quot;Security&amp;quot; 제목을 두는데, 이 글이 독자를 위해 나누는 구분과 같다.&lt;/p&gt;
&lt;h2&gt;버그 수정도 업데이트인가&lt;/h2&gt;
&lt;p&gt;그렇다. 버그 수정은 제품을 바꾸므로, 수정을 내보내는 것은 업데이트다. &lt;a href=&quot;https://semver.org/&quot;&gt;시맨틱 버저닝&lt;/a&gt;에서 하위 호환되는 수정은 패치 릴리스이며, 예를 들어 4.2.0에서 4.2.1이 된다.&lt;/p&gt;
&lt;p&gt;독자가 무언가를 해야 하는지는 별개의 질문이며, 노트가 그것에 답해야 한다. 올바르게 호출하는 쪽이 관찰하는 결과를 바꾸는 수정은 파괴적 변경에 가깝고, 그 경계가 어디인지는 &lt;a href=&quot;https://changeloop.dev/blog/ko/breaking-changes/&quot;&gt;파괴적 변경&lt;/a&gt;에서 설명한다.&lt;/p&gt;
&lt;h2&gt;수정은 언제 독자적인 항목이 되고, 언제 사소한 수정인가&lt;/h2&gt;
&lt;p&gt;사용자가 그 버그를 알아챘을 수 있거나, 그 때문에 시간이나 데이터를 잃었거나, 임시방편을 만들었다면 독자적인 항목을 준다. 팀 밖의 누구도 볼 수 없었다면 짧은 &amp;quot;사소한 수정&amp;quot; 목록으로 묶는다. diff의 크기와 상관없이, 독자의 경험을 기준으로 판단하라.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;독자적인 항목이 되는 경우&lt;/th&gt;
&lt;th&gt;사소한 수정 목록에 들어가는 경우&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;고객이 신고했거나 많은 사람이 겪은 것&lt;/td&gt;
&lt;td&gt;거의 열리지 않는 화면의 외관상 결함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;잘못된 출력, 실패한 작업, 날아간 작업을 일으킨 것&lt;/td&gt;
&lt;td&gt;오타, 간격, 어긋난 아이콘&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;독자의 조치가 필요한 것&lt;/td&gt;
&lt;td&gt;내부 도구나 관리자 페이지의 수정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;최근 릴리스에서 생긴 회귀&lt;/td&gt;
&lt;td&gt;테스트 환경에서만 보인 실패&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;결제, 권한, 데이터와 관련된 것&lt;/td&gt;
&lt;td&gt;로그 문구, 사용자 영향이 없는 의존성 업데이트&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;묶음 속의 각 줄도 무언가를 말해야 한다. &amp;quot;일부 UI 문제를 수정했습니다&amp;quot;는 자리표시자일 뿐이다.&lt;/p&gt;
&lt;h2&gt;회귀는 어떻게 쓰는가&lt;/h2&gt;
&lt;p&gt;그것을 만든 릴리스를 밝히고, 회귀라고 부르고, 그것을 고치는 릴리스를 알려라. 그 버그를 겪은 사람은 이미 고장 났다는 것을 알고 있으므로, 짧고 직접적인 인정이 모호한 표현보다 그들에게 도움이 된다.&lt;/p&gt;
&lt;p&gt;예를 들면 이렇다. &amp;quot;하이픈이 들어간 검색어의 검색 결과가 4.1.0에서 비어서 나왔습니다. 4.1.1에서 수정되었습니다. 하이픈을 피하려고 검색어를 바꾸셨다면 다시 되돌리셔도 됩니다.&amp;quot;&lt;/p&gt;
&lt;p&gt;&amp;quot;검색 안정성을 개선했습니다&amp;quot;는 그 버그 때문에 오후 한나절을 잃은 사람에게는 얼버무리는 것처럼 읽힌다. 원인을 아직 확인하는 중이라면 그렇다고 말하라. &lt;a href=&quot;https://changeloop.dev/blog/ko/emergency-release-notes/&quot;&gt;긴급 릴리스 노트&lt;/a&gt;의 지침대로, 노트가 팀이 아는 것보다 더 확신에 차게 들리면 안 된다.&lt;/p&gt;
&lt;h2&gt;보안 수정은 어떻게 공지하는가&lt;/h2&gt;
&lt;p&gt;심각도를 분명하게 밝히고, 영향받는 버전과 이를 고친 버전을 적고, 업그레이드가 얼마나 급한지 알리고, CVE 식별자가 있다면 포함하라. 사용자가 수정을 적용할 수 있게 된 뒤에만 세부 사항을 공개하며, 신고자가 있었다면 조율된 공개 절차를 따른다.&lt;/p&gt;
&lt;p&gt;순서가 중요하다. 신고자가 비공개로 알려주고, 수정을 출시하고, 사용자가 스스로를 보호할 수 있게 되었을 때 공개 노트를 내보낸다. &lt;a href=&quot;https://www.cisa.gov/coordinated-vulnerability-disclosure-process&quot;&gt;CISA의 조율된 취약점 공개 절차&lt;/a&gt;는 취약점의 신고, 분석, 공개를 조율한다. &lt;a href=&quot;https://www.cve.org/ResourcesSupport/AllResources/CNARules&quot;&gt;CVE Numbering Authority 규칙&lt;/a&gt;은 CVE 레코드가 어떻게 부여되고 게시되는지를 규정하며, GitHub에서는 &lt;a href=&quot;https://docs.github.com/en/code-security/security-advisories/working-with-repository-security-advisories/about-repository-security-advisories&quot;&gt;저장소 보안 권고&lt;/a&gt;로 권고문을 비공개로 작성하고 식별자를 요청할 수 있다.&lt;/p&gt;
&lt;p&gt;보안 항목에는 보통 네 가지 사실이 담긴다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;공격자가 무엇을 할 수 있었는지. 한 문장으로, 개념 증명 없이.&lt;/li&gt;
&lt;li&gt;영향받는 버전과 이를 고친 버전.&lt;/li&gt;
&lt;li&gt;얼마나 급한지. &amp;quot;오늘 업그레이드&amp;quot; 또는 &amp;quot;다음 릴리스 때 업그레이드&amp;quot;.&lt;/li&gt;
&lt;li&gt;악용을 확인했는지, 그리고 신고자가 동의했다면 신고자에 대한 감사.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;악용 절차는 빼라.&lt;/p&gt;
&lt;h2&gt;데이터 손실 수정에 대해 노트는 무엇을 말해야 하는가&lt;/h2&gt;
&lt;p&gt;어떤 데이터가 영향을 받았는지, 내 것이 해당되는지 어떻게 알 수 있는지, 복구할 수 있는지를 말하라. 여기서 &amp;quot;조치가 필요 없음&amp;quot;이 맞는 경우는 드물고, 독자의 첫 질문은 &amp;quot;내 데이터가 사라졌나&amp;quot;이다.&lt;/p&gt;
&lt;p&gt;쓸 만한 항목은 데이터를 잃게 만든 조건(&amp;quot;동기화가 실행되는 동안 폴더를 삭제함&amp;quot;), 그것이 가능했던 기간, 확인 방법(&amp;quot;휴지통을 열어 9월 3일부터 9일 사이의 항목을 찾아보세요&amp;quot;), 그리고 복구 경로를 제시한다. 데이터를 복구할 수 없다면 그렇게 말하라. 영향받은 고객에게는 직접 연락도 하라. 자신의 데이터가 피해를 입었다는 사실을 알게 되는 곳이 릴리스 노트뿐이어서는 안 되기 때문이다.&lt;/p&gt;
&lt;h2&gt;&amp;quot;버그 수정 및 성능 개선&amp;quot;이 나쁜 노트인 이유는 무엇인가&lt;/h2&gt;
&lt;p&gt;독자가 행동할 거리를 전혀 주지 않고, 누군가 기다리던 수정을 숨긴다. 충돌을 신고한 고객은 그것이 고쳐졌는지 알 수 없고, 임시방편을 쓰는 고객은 그것을 제거해야 하는지 알 수 없다.&lt;/p&gt;
&lt;p&gt;정직한 대안은 두 가지다. 릴리스에 독자가 알아챌 만한 것이 없다면 노트를 발행하지 않고 기록은 체인지로그에 맡겨라. 수정이 있다면 독자의 언어로 나열하라.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;이전:
  버그 수정 및 성능 개선.

이후:
  수정: 태그 없는 프로젝트에서 CSV 내보내기가 실패함.
  수정: 다크 모드에서 댓글 입력창의 커서가 안 보임.
  속도: 프로젝트가 100개 넘는 워크스페이스에서
  대시보드가 더 빨리 열림.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;버그 수정 노트는 어디에서 오는가&lt;/h2&gt;
&lt;p&gt;버그를 고친 pull request와 그 계기가 된 신고에서 온다. 신고자의 말이 수정과 함께 전해진다면, 증상의 절반은 이미 쓰인 셈이다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://changeloop.dev/blog/ko/feature-request-vs-bug-report/&quot;&gt;기능 요청과 버그 리포트의 구분&lt;/a&gt;은 신고를 올바르게 분류하는 일이 왜 담당을 결정하는지 설명한다. Changeloop에서는 위젯으로 신고된 버그가 &lt;code&gt;bug&lt;/code&gt; 라벨이 붙은 GitHub issue가 되고, 체인지로그 항목은 병합된 pull request에서 초안이 작성되어 발행되기 전에 사람이 승인하도록 보류된다. &lt;a href=&quot;https://changeloop.dev/release-notes-template&quot;&gt;릴리스 노트 템플릿&lt;/a&gt;은 직접 쓸 때를 위해 같은 항목 형태를 제공한다. 증상, 범위, 기간, 조치다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;버그 수정 릴리스 노트에는 무엇이 들어가야 하는가?&lt;/strong&gt;
각 항목은 사용자가 본 증상, 영향받은 대상, 어느 릴리스나 날짜부터인지, 수정이 완전한지, 그리고 &amp;quot;아무것도 없음&amp;quot;을 포함해 독자가 해야 할 일을 밝혀야 한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;모든 버그 수정을 릴리스 노트에 나열해야 하는가?&lt;/strong&gt;
아니다. 사용자가 알아챘거나, 시간을 잃었거나, 우회한 것만 나열하고, 외관상이거나 내부적인 수정은 짧은 &amp;quot;사소한 수정&amp;quot; 목록으로 묶어라. 체인지로그는 찾아봐야 하는 누구를 위해서든 모든 수정을 보관한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;내가 만든 버그에 대한 릴리스 노트는 어떻게 쓰는가?&lt;/strong&gt;
회귀였다고 말하고, 그것을 만든 릴리스와 고친 릴리스를 밝히고, 독자가 임시방편을 지워도 되는지 알려라. 완곡하게 돌려 말한 표현보다 담백한 서술이 더 낫게 읽힌다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;사용 중인 제품의 릴리스 노트는 어떻게 확인하는가?&lt;/strong&gt;
제품의 도움말 메뉴, 푸터, 문서에 링크된 체인지로그나 릴리스 노트 페이지를 찾아보라. 오픈 소스 프로젝트라면 저장소의 releases 탭을 보면 된다.&lt;/p&gt;
</content:encoded></item><item><title>소프트웨어 제품에서 고객 피드백을 요청하는 방법</title><link>https://changeloop.dev/blog/ko/how-to-ask-for-customer-feedback/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/how-to-ask-for-customer-feedback/</guid><description>사용자가 무언가를 막 끝낸 직후, 그 자리에서 구체적인 질문 하나를 던져라. 순간별로 쓸 수 있는 문구와 피해야 할 나쁜 요청 방식을 정리했다.</description><pubDate>Fri, 02 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;소프트웨어 제품에서 고객 피드백을 요청하려면, 사용자가 방금 한 일에 대해, 그 일을 한 바로 그 자리에서 구체적인 질문 하나를 던져라. 내보내기를 막 마친 직후의 &amp;quot;그 보고서 내보내기는 어땠나요?&amp;quot;에는 답이 돌아온다. 푸터에 놓인 &amp;quot;저희 제품에 대한 생각을 들려주세요&amp;quot;에는 침묵만 돌아온다. 이 글의 나머지는 요청하기에 좋은 순간, 채널, 그리고 정확한 문구를 다룬다.&lt;/p&gt;
&lt;p&gt;이 주제의 조언은 대부분 매장이나 고객 센터를 위해 쓰였다. 소프트웨어 팀은 사용자가 1초 전에 무엇을 했는지 정확히 알고 있으므로, 질문도 바로 그것에 대한 것일 수 있다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;순간&lt;/th&gt;
&lt;th&gt;질문할 곳&lt;/th&gt;
&lt;th&gt;바로 쓸 수 있는 질문&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;작업이 끝난 직후&lt;/td&gt;
&lt;td&gt;앱 안, 결과 옆&lt;/td&gt;
&lt;td&gt;&amp;quot;방금 내보내기가 필요한 대로 됐나요?&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;새 기능을 처음 쓴 뒤&lt;/td&gt;
&lt;td&gt;앱 안, 한 번만&lt;/td&gt;
&lt;td&gt;&amp;quot;일괄 편집으로 무엇을 하려고 하셨나요?&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;지원 티켓이 해결된 뒤&lt;/td&gt;
&lt;td&gt;지원 스레드 안&lt;/td&gt;
&lt;td&gt;&amp;quot;그걸로 해결됐나요, 아직 이상한 부분이 있나요?&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;사용자가 멈추거나 흐름을 떠난 뒤&lt;/td&gt;
&lt;td&gt;하루 뒤 이메일&lt;/td&gt;
&lt;td&gt;&amp;quot;설정 3단계에서 멈추셨네요. 무엇이 방해가 됐나요?&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;30일 동안 꾸준히 쓴 뒤&lt;/td&gt;
&lt;td&gt;실명을 밝힌 사람이 보내는 이메일&lt;/td&gt;
&lt;td&gt;&amp;quot;딱 하나만 바꿀 수 있다면 무엇인가요?&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;사용자가 해지할 때&lt;/td&gt;
&lt;td&gt;해지 과정 안&lt;/td&gt;
&lt;td&gt;&amp;quot;오늘 떠나기로 한 이유는 무엇인가요?&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;요청받은 것을 출시한 뒤&lt;/td&gt;
&lt;td&gt;요청했던 그 자리&lt;/td&gt;
&lt;td&gt;&amp;quot;CSV 가져오기를 요청하셨죠. 지금 출시됐습니다. 쓰시는 경우를 충분히 다루나요?&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;피드백을 요청하기에 적절한 때는 언제인가&lt;/h2&gt;
&lt;p&gt;적절한 때는 사용자가 무언가를 끝낸 직후, 세부 사항이 아직 머릿속에 남아 있을 때다. 행동 뒤에 따라오는 질문은 그 행동에 대한 답을 얻는다. 난데없이 도착한 질문은 그 사람의 그날 기분에 대한 답을 얻거나, 아예 답을 얻지 못한다.&lt;/p&gt;
&lt;p&gt;가입할 때는 묻지 마라. 아직 아무것도 써보지 않았기 때문이다. 작업 도중에도 묻지 마라. 알고 싶은 바로 그 일을 방해하는 셈이기 때문이다. 한 번 답을 받았다면, 알려줄 소식이 생길 때까지는 그 사람을 그냥 두어라.&lt;/p&gt;
&lt;h2&gt;고객 피드백은 어디에서 요청해야 하는가&lt;/h2&gt;
&lt;p&gt;경험이 일어난 바로 그 자리에서 물어라. 앱 안의 프롬프트는 화면에 대한 질문에 맞는다. 지원 스레드는 수정에 대한 질문에 맞는다. 이메일은 일주일 동안 써본 소감이나 사용자가 중간에 그만둔 흐름에 대한 질문에 맞는다. 통화는 예측할 수 없는 질문에 맞는다.&lt;/p&gt;
&lt;p&gt;채널마다 얻는 답의 종류가 다르다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;앱 안:&lt;/strong&gt; 짧고, 즉각적이며, 구체적이지만, 그 자리에 있는 사람들에게서만 나온다. 이미 떠난 사용자에게서는 아무 말도 듣지 못한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;지원 스레드:&lt;/strong&gt; 글을 쓸 만큼 이미 답답했던 사람들에게서 나온다. 고장 난 곳을 찾는 데는 좋지만, 나머지 제품을 판단하는 데는 부족하다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;이메일:&lt;/strong&gt; 더 적은 사람에게서 더 긴 답이 오며, 조용해진 사용자에게 닿을 수 있는 유일한 방법이다. 실명을 밝힌 사람이 보내는 짧은 메모로, 질문은 하나만 담아 써라.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;인터뷰:&lt;/strong&gt; 사람들이 왜 그렇게 하는지 알아내는 방법이다. 일하는 방식을 보여달라고 부탁하고, 그동안 조용히 지켜보라.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;각 채널이 알려주는 내용에 얼마나 무게를 둘지는 &lt;a href=&quot;https://changeloop.dev/blog/ko/feedback-signal-quality/&quot;&gt;피드백 신호의 품질&lt;/a&gt;에서 다룬다.&lt;/p&gt;
&lt;h2&gt;피드백은 어떻게 정중하게 요청하는가&lt;/h2&gt;
&lt;p&gt;대상을 구체적으로 짚고, 왜 묻는지 밝히고, 답하는 데 1분이 들지 않게 하라. 정중한 요청은 그 순간을 명시하고, 사람이 답을 읽는다는 것을 분명히 하며, 방해한 것에 대해 사과하지 않는다.&lt;/p&gt;
&lt;p&gt;정확한 행동(&amp;quot;방금 실행하신 내보내기&amp;quot;)을 말하고, 한 가지만 묻고, 필수 입력란이 없는 자유 서술 칸을 쓰고, 이름으로 서명하라.&lt;/p&gt;
&lt;h2&gt;피드백을 요청하는 좋은 문장은 무엇인가&lt;/h2&gt;
&lt;p&gt;좋은 문장은 특정한 순간에 대한 질문이며 몇 마디로 답할 수 있다. 아래 두 열을 비교해 보라. 왼쪽은 어깨를 으쓱하는 것으로 답할 수 있다. 오른쪽은 사람이 실제로 있었던 일을 떠올려야 한다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;약한 요청&lt;/th&gt;
&lt;th&gt;더 강한 요청&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&amp;quot;피드백 있으신가요?&amp;quot;&lt;/td&gt;
&lt;td&gt;&amp;quot;설정하면서 가장 어려웠던 부분은 무엇인가요?&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;quot;저희 제품은 어떠세요?&amp;quot;&lt;/td&gt;
&lt;td&gt;&amp;quot;지난주에 이걸 무엇에 쓰셨나요?&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;quot;경험을 1점에서 10점으로 평가해 주세요.&amp;quot;&lt;/td&gt;
&lt;td&gt;&amp;quot;오늘 하려던 일을 끝내셨나요?&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;quot;어떻게 개선하면 좋을지 알려주세요.&amp;quot;&lt;/td&gt;
&lt;td&gt;&amp;quot;이번 주에 작업 속도를 늦춘 한 가지는 무엇인가요?&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;quot;저희를 추천하시겠어요?&amp;quot;&lt;/td&gt;
&lt;td&gt;&amp;quot;마지막으로 이걸 누구에게 보여주셨고, 뭐라고 말씀하셨나요?&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;거의 어디서나 통하는 질문이 하나 더 있다. &amp;quot;이게 맞지 않을 때는 대신 무엇을 쓰고 계신가요?&amp;quot; 이 질문은 진짜 경쟁자를 드러내며, 그 경쟁자는 흔히 스프레드시트다.&lt;/p&gt;
&lt;h2&gt;피드백을 요청하는 최악의 방법은 무엇인가&lt;/h2&gt;
&lt;p&gt;최악의 요청은 너무 넓거나, 너무 이르거나, 너무 길거나, 유도하는 것이다. 공통된 문제는 사람이 답하려면 요청하는 쪽이 했어야 할 생각을 대신 해야 한다는 점이다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&amp;quot;20문항 설문에 응해 주세요.&amp;quot;&lt;/strong&gt; 끝까지 마치는 사람은 시간이 가장 많거나 의견이 가장 강한 사람들이다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;로그인 직후 첫 페이지의 팝업.&lt;/strong&gt; 사용자는 무언가를 하러 왔는데 그것을 막았다. 닫아 버리는 것이 유일하게 합리적인 대답이다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;질문 없이 &amp;quot;피드백을 기다립니다!&amp;quot;만 쓴 경우.&lt;/strong&gt; 사용자에게 주제를 직접 만들어 내라고 요구하는 셈이다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;유도 질문: &amp;quot;새 대시보드가 얼마나 마음에 드시나요?&amp;quot;&lt;/strong&gt; 동의는 얻지만 배우는 것은 없다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;후속 질문 없는 점수.&lt;/strong&gt; 10점 만점에 6점은 기분을 알려줄 뿐, 무엇을 바꿔야 하는지는 알려주지 않는다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;묻기만 하고 입을 닫는 것.&lt;/strong&gt; 이는 다음 라운드를 잃게 만든다. 아래에서 다룬다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;제품에 대한 고객 피드백은 무엇이라고 부르는가&lt;/h2&gt;
&lt;p&gt;제품에 대한 피드백은 보통 제품 피드백이라고 부르며, 두 종류로 나뉜다. 버그 리포트는 무언가가 의도대로 작동하지 않는다는 말이고, 기능 요청은 무언가가 빠졌다는 말이다. 이 구분이 누가 먼저 살펴볼지를 결정하며, 그 선은 &lt;a href=&quot;https://changeloop.dev/blog/ko/feature-request-vs-bug-report/&quot;&gt;기능 요청과 버그 리포트의 구분&lt;/a&gt;에서 긋는다. 세 번째 종류인 칭찬은 간직해 두고, 허락을 받아 인용할 가치가 있다.&lt;/p&gt;
&lt;p&gt;첫 선택지로 &amp;quot;버그&amp;quot;와 &amp;quot;기능 요청&amp;quot;을 제시하는 피드백 양식은 이 첫 분류를 대신 해준다.&lt;/p&gt;
&lt;h2&gt;받은 답은 어떻게 처리하는가&lt;/h2&gt;
&lt;p&gt;모든 답을 팀이 이미 일하고 있는 곳에, 그 사람의 말을 그대로 둔 채 넣어라. 인용문 한 줄이 그것을 요약한 글보다 낫다. 유형과 대략적인 긴급도로 태그를 달고, 반복되는 것은 합치고, 결정하라. 만들 것인가, 보류할 것인가, 거절할 것인가.&lt;/p&gt;
&lt;p&gt;거절도 하나의 답이다. &amp;quot;이것은 만들지 않을 것이며, 그 이유는 이렇습니다&amp;quot;라고 말하면 기다림이 끝나며, &lt;a href=&quot;https://changeloop.dev/blog/ko/declining-feature-requests/&quot;&gt;기능 요청 거절&lt;/a&gt;에 그 문구가 있다. 배관 작업은 &lt;a href=&quot;https://changeloop.dev/blog/ko/feature-request-tracking/&quot;&gt;기능 요청 추적&lt;/a&gt;이 다섯 개 채널의 요청을 하나의 목록으로 모으는 방법을 설명한다. 요청을 글로 받는다면 &lt;a href=&quot;https://changeloop.dev/blog/ko/feature-request-template/&quot;&gt;기능 요청 템플릿&lt;/a&gt;이 요청들을 비교 가능한 상태로 유지해 준다.&lt;/p&gt;
&lt;p&gt;Changeloop의 위젯은 접수되는 각 항목을 GitHub issue로 만들어, 피드백이 그것을 고칠 코드 바로 옆에 놓인다. 어떤 도구를 쓰든 규칙은 같다. 목록은 하나, 담당자도 하나, 누군가의 받은 편지함에 방치된 답은 없어야 한다.&lt;/p&gt;
&lt;h2&gt;왜 출시된 내용을 알려야 하는가&lt;/h2&gt;
&lt;p&gt;답한 것이 시간을 들일 가치가 있었음을 그 사람에게 보여준다. 무언가를 말해 준 사용자가 나중에 &amp;quot;출시되었습니다, 감사합니다&amp;quot;라는 말을 들으면 다시 답할 이유가 생긴다. 아무 말도 듣지 못한 사용자는 그 상자를 아무도 읽지 않는다고 결론짓는다.&lt;/p&gt;
&lt;p&gt;그래서 요청의 마지막 단계는 답장이다. 요청한 사람 각자에게, 그들의 언어로, 그들이 쓴 채널에서, 요청이 출시되는 때를 알려라. &lt;a href=&quot;https://changeloop.dev/blog/ko/customer-feedback-loop/&quot;&gt;고객 피드백 루프 닫기&lt;/a&gt;가 그 메커니즘을 설명한다. 발행된 체인지로그 항목이 메시지를 촉발하므로, 요청자는 변경이 실제로 적용된 뒤에야 연락을 받는다. Changeloop에서는 위젯 피드백이 GitHub issue가 되고 병합된 풀 리퀘스트가 그 issue를 닫았을 때 항목을 승인하면, 그 issue에 &amp;quot;Shipped&amp;quot; 댓글이 달리고 위젯에서 제출자에게 그 항목이 보인다. 직접 만든 issue와 GitLab, Bitbucket 저장소에는 댓글이 달리지 않는다. &lt;a href=&quot;https://changeloop.dev/docs&quot;&gt;위젯과 피드 설정&lt;/a&gt;은 문서에 나와 있다.&lt;/p&gt;
&lt;p&gt;답장은 짧아도 된다. &amp;quot;3월에 CSV 가져오기를 요청하셨습니다. 오늘 출시되었고, 사용 방법은 이렇습니다.&amp;quot; 이 답장은 다음에 던질 가장 좋은 질문, 즉 필요한 것을 충분히 다루는지도 마련해 준다.&lt;/p&gt;
&lt;h2&gt;시작하기 위한 계획&lt;/h2&gt;
&lt;p&gt;맨 위의 표에서 사용자가 가장 자주 성공하거나 포기하는 순간 하나를 골라라. 그 순간을 위한 질문 하나를 쓰고, 한 채널에 놓고, 두 번째 프롬프트를 추가하기 전에 2주 동안 모든 답을 읽어라. 구체적인 내용을 준 사람에게는 모두 답장하라.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;고객에게 얼마나 자주 피드백을 요청해야 하는가?&lt;/strong&gt;
요청은 달력이 아니라 이벤트에 묶어라. 사용자가 일주일에 프롬프트를 하나 넘게 보아서는 안 되고, 답한 직후에는 하나도 보여서는 안 된다. 피드백 다음에 보내는 메시지는 그 피드백이 어떻게 되었는지에 대한 답장이어야 한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;사용자를 귀찮게 하지 않고 피드백을 요청하려면 어떻게 해야 하는가?&lt;/strong&gt;
작업 도중이 아니라 작업이 끝난 뒤에 묻고, 질문은 하나로 제한하고, 쉽게 닫을 수 있게 만들어라. 닫았다면 몇 주 동안은 그 선택을 존중하라.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;피드백에 대한 보상을 제공해야 하는가?&lt;/strong&gt;
대개는 필요 없다. 구체적인 질문과 눈에 보이는 답장이 상품권보다 더 큰 무게를 지니며, 보상은 그 보상을 원하는 사람들을 끌어들인다. 20분의 시간을 부탁하는 인터뷰에는 아껴 두어라.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;아무도 답하지 않으면 어떻게 하는가?&lt;/strong&gt;
질문을 좁히고 그 순간에 더 가까이 옮겨라. 예를 들어 화면 하나를 사용한 직후에 묻는 식이다. 그래도 조용하다면 소수의 사용자에게 직접 이메일을 보내고, 그 대화를 바탕으로 더 나은 프롬프트를 써라.&lt;/p&gt;
</content:encoded></item><item><title>제품 로드맵 예시 여섯 가지와 각각이 실패하는 이유</title><link>https://changeloop.dev/blog/ko/product-roadmap-examples/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/product-roadmap-examples/</guid><description>Now/Next/Later, 분기별, 테마, 성과, 공개, 릴리스 로드맵까지 여섯 가지 제품 로드맵 예시를 보여주고, 각각 어떤 팀에 맞고 어디서 무너지는지 정리한다.</description><pubDate>Fri, 02 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;그대로 가져다 쓸 만한 제품 로드맵 예시는 여섯 가지 형식으로 나뉜다. Now/Next/Later, 분기별 타임라인, 테마 로드맵, 성과 로드맵, 공개 로드맵, 그리고 내부 릴리스 로드맵이다. 형식마다 서로 다른 독자의 서로 다른 질문에 답하므로, 올바른 예시란 내 로드맵을 읽을 사람에게 맞는 예시다. 레이아웃은 가장 마지막에 정할 일이다.&lt;/p&gt;
&lt;p&gt;아래의 모든 예시는 가상의 제품, 즉 작은 팀용 업무 앱을 기준으로 하며 모든 항목은 지어낸 것이다. 핵심은 형식 자체다. 각 칸에 무엇이 들어가는지, 실제 항목은 어떻게 생겼는지, 그리고 그 형식이 한 분기 뒤에 무엇 때문에 무너지는지를 본다.&lt;/p&gt;
&lt;h2&gt;좋은 제품 로드맵 예시에는 어떤 것이 있는가&lt;/h2&gt;
&lt;p&gt;좋은 로드맵 예시는 짧고, 독자가 분명하며, 한 종류의 약속만 한다. 지킬 수 있는 약속에 따라 형식을 고르면 된다. 방향, 날짜, 작업의 테마, 결과, 공개 약속, 아니면 배포 일정 중 하나다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;형식&lt;/th&gt;
&lt;th&gt;대상&lt;/th&gt;
&lt;th&gt;잘 맞는 경우&lt;/th&gt;
&lt;th&gt;실패하는 경우&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Now/Next/Later&lt;/td&gt;
&lt;td&gt;회사 전체&lt;/td&gt;
&lt;td&gt;계획이 자주 바뀔 때&lt;/td&gt;
&lt;td&gt;&amp;quot;Next&amp;quot;가 가득 차서 대기열이 될 때&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;분기별 타임라인&lt;/td&gt;
&lt;td&gt;영업, 지원, 경영진&lt;/td&gt;
&lt;td&gt;날짜가 실제 제약일 때&lt;/td&gt;
&lt;td&gt;날짜가 밀리는데 아무도 고치지 않을 때&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;테마 기반&lt;/td&gt;
&lt;td&gt;리더십, 신규 입사자&lt;/td&gt;
&lt;td&gt;이유를 설명하고 싶을 때&lt;/td&gt;
&lt;td&gt;테마가 너무 넓어서 어떤 항목이든 들어맞을 때&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;성과 기반&lt;/td&gt;
&lt;td&gt;제품팀, 엔지니어링&lt;/td&gt;
&lt;td&gt;목표를 측정할 수 있을 때&lt;/td&gt;
&lt;td&gt;지표에 담당자나 데이터가 없을 때&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;공개&lt;/td&gt;
&lt;td&gt;고객&lt;/td&gt;
&lt;td&gt;작게 유지할 수 있을 때&lt;/td&gt;
&lt;td&gt;백로그를 쏟아붓는 곳이 될 때&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;내부 릴리스&lt;/td&gt;
&lt;td&gt;엔지니어링, QA, 지원&lt;/td&gt;
&lt;td&gt;여러 팀이 함께 배포할 때&lt;/td&gt;
&lt;td&gt;전략으로 오해받을 때&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;제품 로드맵 예시는 각각 어떤 모습인가&lt;/h2&gt;
&lt;p&gt;아래 각 형식은 현실적인 항목과 함께 소개하고, 어떤 팀에 맞는지, 언제까지 버티는지, 보통 어떻게 실패하는지를 덧붙인다.&lt;/p&gt;
&lt;h3&gt;Now/Next/Later&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;NOW (이번 달에 만드는 중)
  받은 편지함 저장된 보기
  대형 계정에서도 되는 CSV 내보내기
NEXT (결정됨, 순서는 미정)
  Team 요금제용 SSO
  Slack 알림
LATER (방향일 뿐, 약속 아님)
  모바일 앱
  감사 로그
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;날짜를 약속하고 싶지 않은 회사에 맞는 형식이며, 초기 단계의 많은 팀이 여기에 해당한다. 세 개의 열이 확신의 정도를 그대로 나타내기 때문에 오래간다. &amp;quot;now&amp;quot;는 진행 중이고, &amp;quot;next&amp;quot;는 결정되었으며, &amp;quot;later&amp;quot;는 바람이다. 실패하는 경우는 &amp;quot;later&amp;quot;가 아무도 거절하고 싶지 않은 아이디어를 모두 맡겨두는 주차장이 될 때, 그리고 &amp;quot;next&amp;quot;가 아무도 타임라인이라고 부르지 않는 사이에 슬그머니 순서와 날짜를 얻게 될 때다.&lt;/p&gt;
&lt;h3&gt;타임라인 또는 분기별 로드맵&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;2026년 4분기
  10월  받은 편지함 저장된 보기
  11월  디자인 파트너 5곳과 SSO 베타
  12월  SSO 정식 출시
2027년 1분기
  1월   Slack 알림
  3월   감사 로그 (내보내기만)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;기준으로 삼아 계획을 세워야 하는 영업, 지원, 재무 팀에 맞는 형식이다. 계약, 컨퍼런스, 규정 준수 기한처럼 날짜가 실제 제약일 때 효과가 있다. 날짜가 추측이라면 실패한다. 로드맵에 적힌 월은 몇 주 안에 영업 자료 속의 약속이 되기 때문이다. 이 형식을 쓴다면 분기마다 확정인지 예상인지 표시하고, 두 번째 분기는 첫 번째보다 눈에 띄게 흐리게 처리하라.&lt;/p&gt;
&lt;h3&gt;테마 기반 로드맵&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;THEME: 첫 주 경험
  CSV와 Trello에서 가져오기
  스타터 템플릿
THEME: 더 큰 팀을 위한 준비
  SSO
  감사 로그
  역할 권한
THEME: 수작업 줄이기
  Slack 알림
  반복 작업
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;작업 목록보다 먼저 그 작업이 존재하는 이유를 설명하기 때문에 리더십 보고와 신규 입사자에게 맞는 형식이다. 각 테마가 고객이 관심을 가질 만한 이유와 연결될 때 오래간다. 테마가 &amp;quot;성장&amp;quot;, &amp;quot;품질&amp;quot;처럼 너무 넓어서 모든 항목이 모든 테마에 들어맞게 되면 실패한다. 그 시점에서 그룹화는 아무것도 설명하지 못한다.&lt;/p&gt;
&lt;h3&gt;성과 기반 로드맵&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;GOAL: 설정을 끝내는 신규 팀 늘리기
  지표: 7일 안에 설정 완료, 40%에서 55%로
  시도: CSV 가져오기, 스타터 템플릿
GOAL: 내보내기 관련 지원 티켓 줄이기
  지표: 주당 내보내기 티켓, 30건에서 10건으로
  시도: 대형 계정 내보내기 수정, 내보내기 상태 페이지
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;숫자는 예시일 뿐이고 중요한 것은 레이아웃이다. 목표 하나, 시작값과 목표값이 있는 지표 하나, 그리고 시도해 볼 방법들이다. 해결 방법을 직접 고를 수 있는 신뢰를 받는 제품팀과 엔지니어링 팀에 맞는다. 지표가 존재하고 담당자가 있을 때 효과가 있다. 목표를 측정할 수 없거나, &amp;quot;시도&amp;quot;가 예전과 같은 기능 목록에 성과 문장만 위에 얹은 것이라면 실패한다.&lt;/p&gt;
&lt;h3&gt;고객 대상 공개 로드맵&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;PLANNED
  받은 편지함 저장된 보기
BUILDING
  Slack 알림
SHIPPED
  대형 계정용 CSV 내보내기
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;가장 작은 형식이면서 가장 강한 약속을 한다. 자신의 요청이 전달되었는지 알고 싶은 고객에게 맞는다. 항목이 아주 적고, 날짜가 없고, 제목이 고객의 말로 쓰여 있으면 오래간다. 백로그를 쏟아붓는 곳이 되면 실패한다. 목록에 올린 &amp;quot;어쩌면&amp;quot; 항목 하나하나가 나중에 누군가 물어볼 약속이다. issue 트래커로 공개 로드맵을 운영하는 방법은 &lt;a href=&quot;https://changeloop.dev/blog/ko/public-roadmap/&quot;&gt;세 개의 열로 이루어진 공개 로드맵&lt;/a&gt;에 있으므로 여기서는 반복하지 않는다.&lt;/p&gt;
&lt;h3&gt;내부 릴리스 로드맵&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;릴리스&lt;/th&gt;
&lt;th&gt;목표일&lt;/th&gt;
&lt;th&gt;담당&lt;/th&gt;
&lt;th&gt;의존 대상&lt;/th&gt;
&lt;th&gt;상태&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;5.2&lt;/td&gt;
&lt;td&gt;10월 14일&lt;/td&gt;
&lt;td&gt;플랫폼&lt;/td&gt;
&lt;td&gt;인증 서비스 업그레이드&lt;/td&gt;
&lt;td&gt;코드 완료&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5.3&lt;/td&gt;
&lt;td&gt;11월 11일&lt;/td&gt;
&lt;td&gt;받은 편지함&lt;/td&gt;
&lt;td&gt;저장된 보기 API&lt;/td&gt;
&lt;td&gt;진행 중&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5.4&lt;/td&gt;
&lt;td&gt;12월 9일&lt;/td&gt;
&lt;td&gt;플랫폼&lt;/td&gt;
&lt;td&gt;SSO 업체 계약&lt;/td&gt;
&lt;td&gt;막힘&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;무엇이 함께 배포되고 무엇이 무엇을 막는지 알아야 하는 엔지니어링, QA, 지원 팀에 맞는 형식이다. 주 단위로 정확하고 행마다 담당자가 있을 때 효과가 있다. 누군가 이것을 전략으로 착각하면 실패한다. 배포 일정은 무엇이 언제 나가는지를 알려줄 뿐, 그 릴리스들이 옳은 선택이었는지는 전혀 알려주지 않는다.&lt;/p&gt;
&lt;h2&gt;어떤 제품 로드맵 형식을 선택해야 하는가&lt;/h2&gt;
&lt;p&gt;먼저 독자를 기준으로, 그다음 실제로 가진 확실성의 정도에 따라 고른다. 로드맵을 누가 읽고 그것이 어떤 결정에 도움이 되는지 말할 수 없다면, 위의 어떤 예시도 그것을 구해주지 못한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&amp;quot;제 요청을 들으셨나요?&amp;quot;라고 묻는 고객.&lt;/strong&gt; 공개 형식을 쓰고 항목은 몇 개로 제한하라.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;quot;고객에게 날짜를 말해도 되나요?&amp;quot;라고 묻는 영업과 지원.&lt;/strong&gt; 분기별 타임라인을 쓰되 확정과 예상을 분명히 나누라.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;quot;왜 이 일을 하나요?&amp;quot;라고 묻는 리더십.&lt;/strong&gt; 테마를 쓰고, 데이터가 있다면 성과 형식을 쓰라.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;매달 방향이 바뀌는 팀.&lt;/strong&gt; Now/Next/Later를 쓰고 날짜를 적고 싶은 유혹을 참으라.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;quot;무엇이 언제 나가나요?&amp;quot;라고 묻는 엔지니어.&lt;/strong&gt; 릴리스 로드맵을 쓰고 전략 로드맵과 분리해 두라.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;대부분의 팀은 결국 두 개를 갖게 된다. 앞의 네 가지 중 하나인 전략 로드맵, 그리고 그 아래의 릴리스 일정이다. 공개 로드맵은 그때 전략 로드맵을 걸러낸 보기가 되어, 책임질 각오가 되어 있는 것만 보여준다.&lt;/p&gt;
&lt;h2&gt;제품 로드맵은 어떻게 쓰는가&lt;/h2&gt;
&lt;p&gt;독자를 정하고, 그들의 질문에 맞는 형식을 고르고, 회의에서 방어할 수 있는 항목만 적고, 항목마다 상태와 담당자를 붙이면 된다. 그리고 발행하기 전에 얼마나 자주 검토할지를 정하라.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;독자와 결정을 정한다.&lt;/strong&gt; &amp;quot;지원팀이 SSO에 대해 고객에게 무엇을 말할지 결정한다&amp;quot;는 이유가 된다. &amp;quot;모두가 로드맵을 봐야 한다&amp;quot;는 설계할 대상을 주지 않는다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;이미 아는 것에서 시작한다.&lt;/strong&gt; &lt;a href=&quot;https://changeloop.dev/blog/ko/prioritizing-feature-requests/&quot;&gt;설명할 수 있는 기준으로 순위를 매긴&lt;/a&gt; 열린 요청이 브레인스토밍보다 나은 재료다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;각 항목을 고객의 결과로 쓴다.&lt;/strong&gt; &amp;quot;자주 쓰는 필터 유지하기&amp;quot;가 &amp;quot;저장된 보기 지속성 구현&amp;quot;보다 잘 읽히고, 고객에게 자기 문제인지 알려준다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;로드맵에 담지 않을 것을 정한다.&lt;/strong&gt; 날짜, 추정치, 아이디어 백로그가 흔한 세 가지 제외 대상이다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;검토일을 정한다.&lt;/strong&gt; 예정된 검토가 없는 로드맵에는 예정 없는 장례식이 기다린다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;제품 로드맵을 최신 상태로 유지하려면&lt;/h2&gt;
&lt;p&gt;작업이 움직일 때 작업을 추적하는 바로 그 장소에서 항목을 옮기고, 항목이 출시되거나 폐기될 때 무슨 일이 있었는지 기록하면 된다. 별도의 도구에서 누군가 손으로 갱신하는 로드맵은 누구의 일상 업무도 아니기 때문에 낡아 간다.&lt;/p&gt;
&lt;p&gt;가장 저렴한 단일 진실 공급원은 issue 트래커다. 로드맵의 각 열이 issue의 라벨 하나에 대응한다면, 라벨이 바뀔 때 로드맵이 바뀌고 다시 입력할 것은 없다. Changeloop의 방식은 &lt;code&gt;roadmap:planned&lt;/code&gt;, &lt;code&gt;roadmap:building&lt;/code&gt;, &lt;code&gt;roadmap:shipped&lt;/code&gt; 라벨을 쓰며, issue에 두 개가 붙어 있으면 가장 많이 진행된 쪽이 이긴다. 카드를 shipped로 옮기는 일도 여전히 별도의 라벨 변경이므로, 체인지로그 항목을 승인하는 검토 과정에 포함시켜라.&lt;/p&gt;
&lt;p&gt;그 항목이 나머지 절반이다. 항목이 출시되면 체인지로그는 고객의 언어로 무엇이 바뀌었는지 알려주고, 그것을 요청한 사람에게 알릴 수 있다. 이 고리를 닫는 것이 &lt;a href=&quot;https://changeloop.dev/blog/ko/customer-feedback-loop/&quot;&gt;고객 피드백 루프&lt;/a&gt;의 핵심이며, 로드맵은 그 루프에서 무언가 출시되기 전에 고객이 볼 수 있는 구간이다. 항목을 폐기한다면 그렇다고 말하라. 공개적인 &amp;quot;아니요&amp;quot;도 그 요청을 마무리하며, &lt;a href=&quot;https://changeloop.dev/blog/ko/declining-feature-requests/&quot;&gt;기능 요청 거절&lt;/a&gt;에서 그 표현 방법을 다룬다. 완성된 항목이 어떻게 읽히는지 보고 싶은 팀은 &lt;a href=&quot;https://changeloop.dev/changelog-examples&quot;&gt;체인지로그 예시&lt;/a&gt;를 둘러볼 수 있다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;가장 단순한 제품 로드맵 형식은 무엇인가?&lt;/strong&gt;
Now/Next/Later다. 열이 세 개이고, 날짜가 필요 없으며, 항목을 확실성에 따라 묶는다. 방향을 자주 바꾸는 작은 팀에게는 창피할 만큼 크게 틀리기가 가장 어려운 형식이기도 하다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;제품 로드맵에는 항목이 몇 개나 있어야 하는가?&lt;/strong&gt;
생각보다 적게 둬라. 공개 로드맵은 모든 열을 합쳐 열 개 미만이면 충분하고, 내부 전략 로드맵도 열두 개를 넘을 일은 드물다. 그보다 많아지면 머리말만 예쁜 백로그다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;제품 로드맵에 날짜를 넣어야 하는가?&lt;/strong&gt;
날짜가 실제 제약일 때만, 그리고 가장 가까운 분기에 대해서만 넣는다. 그 너머는 열이나 테마를 쓴다. 로드맵의 날짜는 의도했든 아니든 영업 대화에서 약속이 된다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;제품 로드맵과 릴리스 계획의 차이는 무엇인가?&lt;/strong&gt;
로드맵은 무엇을 왜 만들려는지를 말하고, 릴리스 계획은 어떤 빌드가 어느 날짜에 나가며 누가 책임지는지를 말한다. 로드맵은 전략이 바뀔 때 바뀌고, 릴리스 계획은 작업이 바뀔 때 바뀐다.&lt;/p&gt;
</content:encoded></item><item><title>자주 배포하는 팀을 위한 릴리스 관리 프로세스</title><link>https://changeloop.dev/blog/ko/release-management-process/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/release-management-process/</guid><description>소프트웨어 팀을 위한 릴리스 관리 프로세스를 범위 계획부터 회고까지 일곱 단계로 나누고, 단계마다 담당자와 완료 기준을 정했다. DORA 지표도 소개한다.</description><pubDate>Fri, 02 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;릴리스 관리 프로세스는 변경이 &amp;quot;병합됨&amp;quot;에서 &amp;quot;프로덕션에서 실행 중이며 영향받는 사람들에게 설명됨&amp;quot;에 이르기까지 거치는 일련의 단계다. 자주 배포하는 팀이라면 일곱 단계로 정리된다. 범위 계획, 변경 분리, 빌드와 테스트, 승인, 배포와 검증, 커뮤니케이션, 회고다. 단계마다 이름이 지정된 담당자 한 명과 완료 기준 하나가 필요하며, 그렇지 않으면 그 단계는 조용히 사라진다.&lt;/p&gt;
&lt;p&gt;이 가이드는 엔지니어 5명에서 50명 규모에서 매주 또는 매일 배포하고, 프로세스가 방해되지 않기를 바라는 팀을 가정한다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;단계&lt;/th&gt;
&lt;th&gt;담당&lt;/th&gt;
&lt;th&gt;완료 기준&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;1. 범위 계획&lt;/td&gt;
&lt;td&gt;제품 또는 기술 리드&lt;/td&gt;
&lt;td&gt;이번 릴리스의 변경 목록이 작성되어 있고, 위험한 것에는 표시가 되어 있다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. 브랜치 또는 플래그&lt;/td&gt;
&lt;td&gt;변경을 맡은 엔지니어&lt;/td&gt;
&lt;td&gt;작업이 수명이 짧은 브랜치나 플래그 뒤에 있어서 main이 항상 릴리스 가능하다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. 빌드와 테스트&lt;/td&gt;
&lt;td&gt;CI, 실패 시 작성자가 대기&lt;/td&gt;
&lt;td&gt;출시될 바로 그 커밋에서 파이프라인이 녹색이다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. 승인&lt;/td&gt;
&lt;td&gt;리뷰어, 위험한 변경은 릴리스 매니저 추가&lt;/td&gt;
&lt;td&gt;리뷰가 끝났고, 롤백 경로가 지정되었고, 진행 또는 중단 결정이 기록되었다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5. 배포와 검증&lt;/td&gt;
&lt;td&gt;릴리스 매니저 또는 당직 엔지니어&lt;/td&gt;
&lt;td&gt;배포되었고, 스모크 체크가 통과하고, 오류율과 지연 시간이 릴리스 전 기준선과 일치한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6. 커뮤니케이션&lt;/td&gt;
&lt;td&gt;변경을 이해하는 사람이 쓰고, 이해하지 못하는 사람이 편집&lt;/td&gt;
&lt;td&gt;릴리스 노트가 사용자가 읽는 곳에 발행되었고, 지원과 영업에 공유되었다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7. 회고&lt;/td&gt;
&lt;td&gt;릴리스 매니저&lt;/td&gt;
&lt;td&gt;지표를 확인했고, 잘못된 것마다 담당자와 해결책이 있다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;릴리스 관리 프로세스란 무엇인가&lt;/h2&gt;
&lt;p&gt;변경이 사용자에게 도달하기까지 따르는 반복 가능한 경로다. 범위, 빌드, 테스트, 승인, 배포, 검증, 공지, 그리고 되돌아보기다. 이를 문서로 남기는 이유는 모든 릴리스가 같은 경로를 따르게 하기 위해서이며, 그러면 휴가 중인 사람, 신입, 새벽 2시의 당직 엔지니어가 누구에게도 방법을 묻지 않고 그것을 실행할 수 있다.&lt;/p&gt;
&lt;h2&gt;릴리스 관리의 유형에는 어떤 것이 있는가&lt;/h2&gt;
&lt;p&gt;실무에서는 세 가지 유형이 있다. 지속적 배포, 정기 릴리스, 규제 대상 변경 관리다. 릴리스 전에 얼마나 많은 일이 이루어지는지, 얼마나 자동화되어 있는지가 다르다. 지속적 배포는 병합된 모든 변경을 출시하고, 정기 릴리스는 변경을 묶어 열차에 태우고, 규제 대상 변경 관리는 공식 승인과 감사 기록을 더한다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;지속적 배포&lt;/th&gt;
&lt;th&gt;정기 릴리스&lt;/th&gt;
&lt;th&gt;규제 대상 또는 ITIL 변경 관리&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;릴리스 단위&lt;/td&gt;
&lt;td&gt;병합된 pull request 하나&lt;/td&gt;
&lt;td&gt;매주 또는 격주의 묶음&lt;/td&gt;
&lt;td&gt;변경 요청 하나&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;범위 단계&lt;/td&gt;
&lt;td&gt;암묵적, 병합이 곧 범위&lt;/td&gt;
&lt;td&gt;릴리스 계획 회의&lt;/td&gt;
&lt;td&gt;위험 등급이 있는 변경 기록&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;승인&lt;/td&gt;
&lt;td&gt;코드 리뷰와 자동 검사&lt;/td&gt;
&lt;td&gt;릴리스 매니저가 묶음을 승인&lt;/td&gt;
&lt;td&gt;변경 자문 위원회 또는 위임된 승인자&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;위험 통제&lt;/td&gt;
&lt;td&gt;기능 플래그, 카나리, 빠른 롤백&lt;/td&gt;
&lt;td&gt;스테이징 숙성, 릴리스 후보&lt;/td&gt;
&lt;td&gt;문서화된 철수 계획, 유지보수 시간대&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;일반적인 주기&lt;/td&gt;
&lt;td&gt;하루에 여러 번&lt;/td&gt;
&lt;td&gt;매주에서 매달&lt;/td&gt;
&lt;td&gt;변경 일정에 따라 결정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;약점&lt;/td&gt;
&lt;td&gt;무엇이 바뀌었는지 사용자에게 아무도 알리지 않음&lt;/td&gt;
&lt;td&gt;큰 묶음이 문제를 일으킨 변경을 가림&lt;/td&gt;
&lt;td&gt;프로세스에 드는 시간이 변경 자체를 압도함&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;대부분의 팀은 이것들이 섞여 있다. SaaS 제품은 지속적으로 배포하면서 모바일 앱은 주간 열차로 내보내고, 감사 담당자가 신경 쓰는 결제 서비스 하나만 공식 변경 기록을 따를 수 있다. 유형은 회사 단위가 아니라 서비스 단위로 고르라. 변경이 점진적으로만 공개되는 곳에서는 릴리스와 공지가 별개의 이벤트가 되며, 이 경우는 &lt;a href=&quot;https://changeloop.dev/blog/ko/feature-flags-feature-requests/&quot;&gt;피처 플래그 릴리스 노트&lt;/a&gt;에서 다룬다.&lt;/p&gt;
&lt;h2&gt;릴리스 매니저의 책임은 무엇인가&lt;/h2&gt;
&lt;p&gt;릴리스 매니저는 변경이 프로덕션에 이르는 경로를 책임진다. 릴리스 일정을 관리하고, 변경이 준비되었는지 판단하고, 배포를 실행하거나 감독하고, 롤백을 결정하고, 사용자에게 알리는 일을 챙기고, 이후의 회고를 진행한다.&lt;/p&gt;
&lt;p&gt;릴리스 전에는 범위를 확인하고 위험한 변경마다 롤백 경로가 있는지 점검한다. 릴리스 중에는 배포 체크리스트를 실행하고, 프로덕션 지표의 처음 몇 분을 지켜보며 롤백을 일찍 결정한다. 릴리스 후에는 노트가 나갔는지 확인하고, 프로세스에서 고쳐야 할 것을 기록한다.&lt;/p&gt;
&lt;p&gt;작은 팀이라면 이 역할을 매주 돌려 맡고, 누구도 구전 지식이 필요하지 않도록 체크리스트를 써 두라. 독립적으로 릴리스되는 패키지가 많은 &lt;a href=&quot;https://changeloop.dev/blog/ko/monorepo-changelogs/&quot;&gt;모노레포&lt;/a&gt;는 보통 패키지마다 릴리스 담당자가 한 명씩 필요하며, 그렇지 않으면 이 역할이 병목이 된다.&lt;/p&gt;
&lt;h2&gt;릴리스 관리의 핵심 KPI는 무엇인가&lt;/h2&gt;
&lt;p&gt;DORA의 소프트웨어 전달 지표를 추적하고, 직접 만든 지표를 하나 더하라. 사용자에게 알리기까지 걸리는 시간이다. DORA의 연구는 다섯 가지 지표를 꼽으며, 처리량(변경 리드 타임, 배포 빈도, 실패한 배포의 복구 시간)과 불안정성(변경 실패율, 배포 재작업률)으로 나뉜다.&lt;/p&gt;
&lt;p&gt;DORA의 가이드는 이를 쉬운 말로 정의한다(&lt;a href=&quot;https://dora.dev/guides/dora-metrics/&quot;&gt;dora.dev, software delivery metrics&lt;/a&gt;).&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;KPI&lt;/th&gt;
&lt;th&gt;측정 대상&lt;/th&gt;
&lt;th&gt;주의할 점&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;변경 리드 타임&lt;/td&gt;
&lt;td&gt;버전 관리에 커밋된 시점부터 프로덕션에 배포되기까지의 시간&lt;/td&gt;
&lt;td&gt;숫자가 늘어난다면 보통 리뷰나 승인에 대기열이 생겼다는 뜻이다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;배포 빈도&lt;/td&gt;
&lt;td&gt;얼마나 자주 배포하는지, 또는 배포 사이의 시간&lt;/td&gt;
&lt;td&gt;빈도가 떨어지면 묶음이 커지고 있다는 뜻이다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;실패한 배포의 복구 시간&lt;/td&gt;
&lt;td&gt;즉각적인 개입이 필요한 배포에서 복구하는 데 걸리는 시간&lt;/td&gt;
&lt;td&gt;롤백과 알림의 문제가 여기서 드러난다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;변경 실패율&lt;/td&gt;
&lt;td&gt;롤백이나 핫픽스가 필요한 배포의 비율&lt;/td&gt;
&lt;td&gt;묶음이 너무 크거나 테스트가 부실하면 오른다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;배포 재작업률&lt;/td&gt;
&lt;td&gt;프로덕션 장애 때문에 계획 없이 이루어진 배포의 비율&lt;/td&gt;
&lt;td&gt;교훈보다 수정이 더 빨리 출시되고 있다는 신호다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;사용자에게 알리기까지의 시간&lt;/td&gt;
&lt;td&gt;프로덕션 배포부터 사용자에게 보이는 노트가 발행되기까지의 분&lt;/td&gt;
&lt;td&gt;직접 측정하라. 어떤 프레임워크도 제공하지 않는다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;예전 자료는 네 가지 핵심 지표를 나열하고 복구를 &amp;quot;time to restore&amp;quot;라고 부른다. 현재의 가이드는 위의 다섯 가지를 쓴다.&lt;/p&gt;
&lt;p&gt;같은 가이드는 이 지표들을 목표로 삼지 말라고 경고한다. &amp;quot;연말까지 모든 것을 하루에 여러 번 배포한다&amp;quot; 같은 목표를 세우면 팀이 숫자를 조작하게 되며, 이 지표들은 회사 전체로 뭉뚱그리는 것이 아니라 애플리케이션이나 서비스별로 읽도록 되어 있다. 이 모두를 개선하기 위한 실용적인 조언은 변경 하나하나의 크기를 줄이는 것이다. 작은 변경일수록 리뷰하기도, 파이프라인을 통과시키기도, 복구하기도 쉽기 때문이다.&lt;/p&gt;
&lt;h2&gt;릴리스 커뮤니케이션은 릴리스 관리 프로세스에서 어디에 들어가는가&lt;/h2&gt;
&lt;p&gt;여섯 번째 단계이며, 다른 모든 단계처럼 담당자와 완료 기준이 있다. 노트가 사용자가 읽는 곳에 발행되었고, 내부 팀에 공유되었다는 것이다. 팀들이 가장 자주 건너뛰는 단계인데, 배포 도구는 코드가 반영되는 순간 성공이라고 보고하기 때문이다.&lt;/p&gt;
&lt;p&gt;이 단계를 일정대로 지키는 가장 저렴한 방법은 릴리스가 출시될 때가 아니라 변경이 병합될 때 항목을 쓰는 것이다. pull request에는 이미 제목, 작성자, 연결된 issue, 맥락이 있다. 그것으로 만든 초안은 일주일 뒤에 기억에 의존해서 쓰는 대신 편집하는 대상이 된다. 이것이 &lt;a href=&quot;https://changeloop.dev/blog/ko/changelog-automation/&quot;&gt;체인지로그 자동화&lt;/a&gt;의 발상이다. 병합할 때 초안을 만들고, 사람이 승인하도록 보류하고, 하나의 원본에서 모든 곳에 발행한다. Changeloop도 이렇게 동작하며, 병합된 pull request로 AI가 항목 초안을 만들고 무엇이든 발행되기 전에 승인을 위해 보류해 둔다.&lt;/p&gt;
&lt;p&gt;미리 계획해 둘 만한 변형이 두 가지 있다. 지원과 영업에는 고객과 다른 노트가 필요하며, &lt;a href=&quot;https://changeloop.dev/blog/ko/internal-release-notes/&quot;&gt;내부용 릴리스 노트&lt;/a&gt;가 그 용도다. 장애 대응으로 나가는 릴리스에는 평소의 초안 작성 과정을 거칠 시간이 없으므로, &lt;a href=&quot;https://changeloop.dev/blog/ko/emergency-release-notes/&quot;&gt;긴급 릴리스 노트&lt;/a&gt;에 설명된 대로 짧은 템플릿을 준비해 두라. 고객용 버전의 출발점이 되는 형태는 &lt;a href=&quot;https://changeloop.dev/release-notes-template&quot;&gt;릴리스 노트 템플릿&lt;/a&gt;에서 얻을 수 있다.&lt;/p&gt;
&lt;h2&gt;프로세스를 가볍게 유지하려면&lt;/h2&gt;
&lt;p&gt;기계가 확인할 수 있는 모든 완료 기준은 자동화하고, 판단이 필요한 일에만 사람을 쓰라. 녹색 파이프라인, 대시보드의 배포 마커, 병합된 pull request마다의 체인지로그 초안 항목은 확인 가능하다. 롤백 계획이 믿을 만한지, 노트가 고객에게 이해되는지는 사람이 해야 한다.&lt;/p&gt;
&lt;p&gt;프로세스를 시험하려면 지난달의 릴리스 하나를 골라, 팀 밖의 누군가가 기록만 보고도 무엇이 출시되었는지, 누가 승인했는지, 어떻게 검증했는지, 사용자에게 언제 알렸는지 말할 수 있는지 물어보라. 빈틈이 있다면 그것이 다음 개선 과제다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;릴리스 관리와 변경 관리의 차이는 무엇인가?&lt;/strong&gt;
릴리스 관리는 일련의 변경을 빌드하고, 테스트하고, 배포하고, 공지하게 만든다. ITIL에서 말하는 변경 관리는 변경 하나하나를 둘러싼 승인과 위험 프로세스다. 자주 배포하는 팀은 승인을 코드 리뷰와 자동 검사에 녹여 넣는다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;얼마나 자주 릴리스해야 하는가?&lt;/strong&gt;
테스트와 롤백 경로가 허용하는 만큼 자주, 많은 웹 팀에게는 매일 또는 그 이상이다. DORA의 지침은 변경 하나하나의 크기를 줄이라는 것이며, 작은 변경이 리뷰하고 복구하기 더 쉽기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;작은 팀에도 릴리스 매니저가 필요한가?&lt;/strong&gt;
책임은 필요하지만 직함이 꼭 필요한 것은 아니다. 엔지니어들 사이에서 역할을 돌려 맡고, 당번인 사람에게 문서로 된 체크리스트를 주고, 일곱 단계 하나하나를 누군가 맡고 있도록 하라.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;릴리스 체크리스트에는 무엇이 들어가야 하는가?&lt;/strong&gt;
범위 확인, 출시 커밋에서의 녹색 파이프라인, 지정된 롤백 경로, 기록된 승인, 배포 후 스모크 체크, 기준선과 비교한 지표, 발행된 릴리스 노트, 지원팀 공유, 그리고 예정된 회고다. 한 페이지로 유지하라.&lt;/p&gt;
</content:encoded></item><item><title>모든 종류의 변경에 쓸 수 있는 릴리스 노트 예시</title><link>https://changeloop.dev/blog/ko/release-notes-examples/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/release-notes-examples/</guid><description>새 기능, 수정, 파괴적 변경, 보안 수정, 비추천, 앱스토어 노트, 내부 노트까지 변경 종류별 릴리스 노트 예시와 그 문구가 효과적인 이유를 보여준다.</description><pubDate>Fri, 02 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;가장 좋은 릴리스 노트 예시는 짧고, 누가 영향을 받는지 밝히고, 다음에 무엇을 해야 하는지 말한다. 아래에는 앞으로 내보낼 변경의 종류마다 예시를 하나씩, 그것이 효과적인 이유와 함께 실었다. 형태를 그대로 가져다 쓰고 내용만 여러분의 사실로 바꾸면 된다.&lt;/p&gt;
&lt;p&gt;모든 예시는 Tidepool이라는 가상의 청구서 앱을 위해 지어낸 것이다.&lt;/p&gt;
&lt;h2&gt;좋은 릴리스 노트 예시들은 무엇이 공통적인가&lt;/h2&gt;
&lt;p&gt;무엇이 바뀌었는지, 그리고 그에 대해 해야 할 일이 있다면 무엇인지를 사용자의 언어로 알려준다. 변경의 종류마다 맡은 역할이 다르므로 형태도 조금씩 달라진다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;변경 유형&lt;/th&gt;
&lt;th&gt;항목에 반드시 들어갈 것&lt;/th&gt;
&lt;th&gt;위치&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;새 기능&lt;/td&gt;
&lt;td&gt;독자가 이제 할 수 있는 일과 누구에게 제공되는지&lt;/td&gt;
&lt;td&gt;노트의 맨 위&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;개선&lt;/td&gt;
&lt;td&gt;무엇이 더 빨라지거나 쉬워졌는지, 있다면 수치와 함께&lt;/td&gt;
&lt;td&gt;기능 뒤&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;버그 수정&lt;/td&gt;
&lt;td&gt;독자가 본 증상과 해결되었다는 사실&lt;/td&gt;
&lt;td&gt;개선 뒤&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;파괴적 변경&lt;/td&gt;
&lt;td&gt;영향받는 대상, 날짜, 마이그레이션&lt;/td&gt;
&lt;td&gt;항상 맨 먼저&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;보안 수정&lt;/td&gt;
&lt;td&gt;무엇이 노출되었는지, 악용되었는지, 해야 할 일&lt;/td&gt;
&lt;td&gt;맨 먼저&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;비추천&lt;/td&gt;
&lt;td&gt;사라지는 것, 종료일, 대체 수단&lt;/td&gt;
&lt;td&gt;상단 근처&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;앱스토어 노트&lt;/td&gt;
&lt;td&gt;변경마다 평이한 한 문장, 글자 수 제한 이내&lt;/td&gt;
&lt;td&gt;스토어 목록&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;내부 노트&lt;/td&gt;
&lt;td&gt;무엇이 바뀌었는지와 고객에게 무엇을 말할지&lt;/td&gt;
&lt;td&gt;지원과 영업 채널&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;좋은 새 기능 노트는 어떤 모습인가&lt;/h2&gt;
&lt;p&gt;좋은 기능 노트는 독자가 이제 할 수 있는 일로 시작하고, 그것을 받는 요금제나 역할을 밝힌다. 구현 이야기는 건너뛴다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;고객의 언어로 청구서를 보내세요.&lt;/strong&gt;
이제 고객마다 언어를 선택할 수 있으며, 그 고객의 청구서, 알림 메일, 결제 페이지가 선택한 언어를 따릅니다. 프랑스어, 독일어, 스페인어, 포르투갈어를 모든 요금제에서 사용할 수 있습니다. 고객 페이지의 결제 환경설정에서 설정하세요.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;헤드라인은 독자가 소리 내어 말할 법한 문구이고, 본문은 범위와 위치를 알려준다. 굵은 글씨 줄만 훑어본 독자도 무엇이 출시되었는지 안다. 더 넓은 방법론은 &lt;a href=&quot;https://changeloop.dev/blog/ko/how-to-write-release-notes/&quot;&gt;릴리스 노트를 쓰는 방법&lt;/a&gt;에 있다.&lt;/p&gt;
&lt;h2&gt;좋은 개선 노트는 어떤 모습인가&lt;/h2&gt;
&lt;p&gt;개선 노트는 독자가 체감할 변경을 설명하고, 측정한 수치가 있다면 그것을 붙인다. 수치가 없다면 독자가 더는 하지 않아도 되는 일을 말한다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;청구서 목록이 약 세 배 빨리 열립니다.&lt;/strong&gt;
청구서가 5,000건이 넘는 계정은 목록이 뜨기까지 약 9초를 기다려야 했습니다. 이제 약 3초 만에 열립니다. 조치가 필요 없습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;quot;성능 개선&amp;quot;은 독자에게 아무것도 알려주지 않지만, 9초 대 3초는 월요일 아침에 직접 확인해 볼 수 있는 주장이다. 마지막의 &amp;quot;조치가 필요 없습니다&amp;quot;는 모든 독자가 가진 질문에 답한다.&lt;/p&gt;
&lt;h2&gt;좋은 버그 수정 노트는 어떤 모습인가&lt;/h2&gt;
&lt;p&gt;버그 수정 노트는 코드의 원인이 아니라 사용자가 본 증상을 설명하고, 다시 해야 할 일이 있는지를 말한다. 아무도 눈치채지 못한 수정은 하단의 목록에 넣어도 된다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;수정됨: 알림 메일이 마감일에 두 번 발송되던 문제.&lt;/strong&gt;
청구서의 마감일이 월말인 경우 일부 고객이 똑같은 알림을 두 번 받았습니다. 이 문제는 수정되었습니다. 이미 발송된 알림은 영향받지 않으며, 다시 보낼 필요도 없습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;헤드라인이 &amp;quot;수정됨&amp;quot;으로 시작하므로 훑어보는 사람이 한눈에 분류할 수 있고, 실제 조건(월말)이 바로 뒤따른다.&lt;/p&gt;
&lt;h2&gt;파괴적 변경의 릴리스 노트는 어떻게 쓰는가&lt;/h2&gt;
&lt;p&gt;파괴적 변경 노트는 날짜와 영향받는 대상으로 시작하고, 같은 항목 안에 마이그레이션을 함께 담는다. 독자가 놓쳐서는 안 되는 유일한 항목이므로 릴리스 노트의 맨 처음에 놓는다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;2026년 12월 1일부터 웹훅 서명이 필수가 됩니다.&lt;/strong&gt;
그 날짜부터 Tidepool은 서명되지 않은 웹훅 페이로드를 보내지 않습니다. &lt;code&gt;Tidepool-Signature&lt;/code&gt; 헤더를 확인하지 않고 웹훅을 받는 모든 분이 해당됩니다. 마이그레이션하려면 설정, 개발자 메뉴의 시크릿으로 헤더를 검증하세요. 이미 서명을 검증하고 있다면 조치가 필요 없습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;날짜가 헤드라인에 있어서 훑어보아도 살아남는다. 영향받는 대상은 그들이 하는 일로 지칭하고, 마지막 문장은 이미 문제없는 사람들을 놓아주므로 지원 부담이 줄어든다. 변경이 해당되는지 판단하는 방법은 &lt;a href=&quot;https://changeloop.dev/blog/ko/breaking-changes/&quot;&gt;파괴적 변경&lt;/a&gt; 가이드에서 다룬다.&lt;/p&gt;
&lt;h2&gt;보안 수정 노트는 어떤 모습인가&lt;/h2&gt;
&lt;p&gt;보안 노트는 무엇이 노출되었는지, 누군가 악용했는지, 누가 영향을 받는지, 그리고 그들이 무엇을 해야 하는지를 말한다. 사실에 충실하고 차분하게 쓴다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;보안: 비밀번호 재설정 링크가 재사용될 수 있었습니다.&lt;/strong&gt;
2026년 9월 3일부터 17일까지, 비밀번호 재설정 링크가 한 번 사용된 뒤에도 유효한 상태로 남아 있었습니다. 악용된 흔적은 발견하지 못했습니다. 문제는 수정되었으며, 남아 있던 모든 재설정 링크는 무효화되었습니다. 그 기간에 재설정을 요청하셨다면 새 링크를 요청해 주세요.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;정확한 기간이 있어서 독자가 자신의 노출 여부를 판단할 수 있고, 악용 여부에 대한 문장은 누구나 가장 먼저 던지는 질문에 답한다. &amp;quot;잠재적인 문제&amp;quot;라는 표현은 은폐처럼 읽히므로, 아는 것을 그대로 말하라.&lt;/p&gt;
&lt;h2&gt;비추천 공지는 어떻게 쓰는가&lt;/h2&gt;
&lt;p&gt;비추천 공지는 제거되는 대상을 밝히고, 확정된 종료일을 알리고, 대체 수단을 가리킨다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;v1 청구서 엔드포인트는 비추천되었으며 2027년 3월 1일에 종료됩니다.&lt;/strong&gt;
&lt;code&gt;GET /v1/invoices&lt;/code&gt;는 2027년 3월 1일까지 계속 작동하고, 그 이후에는 &lt;code&gt;410 Gone&lt;/code&gt;을 반환합니다. 같은 필드에 &lt;code&gt;currency&lt;/code&gt;가 추가된 &lt;code&gt;GET /v2/invoices&lt;/code&gt;를 사용하세요. 이제 v1 응답에는 종료일이 담긴 &lt;code&gt;Sunset&lt;/code&gt; 헤더가 포함됩니다. 나란히 비교한 마이그레이션 가이드는 문서에 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;영향받는 사람들이 검색하는 것이 엔드포인트 이름이므로 헤드라인에 넣었고, 대체 수단은 제거 소식 바로 옆에 놓았다. &lt;code&gt;Sunset&lt;/code&gt; 헤더는 어떤 호출이 아직 예전 버전을 쓰는지 개발자에게 알려준다. 더 자세한 내용은 &lt;a href=&quot;https://changeloop.dev/blog/ko/api-deprecation/&quot;&gt;API 비추천 처리&lt;/a&gt;에 있다.&lt;/p&gt;
&lt;h2&gt;앱스토어 릴리스 노트는 어떤 모습인가&lt;/h2&gt;
&lt;p&gt;앱스토어 노트는 평이한 두세 문장이다. 대부분의 사람은 첫 줄만 읽기 때문이다. 사용자가 알아차릴 변경으로 시작하라.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;종이 영수증을 스캔하면 Tidepool이 금액, 날짜, 거래처를 채워 줍니다. 이제 다크 모드가 휴대폰 설정을 따릅니다. 알림에서 청구서를 열 때 앱이 종료되던 문제도 수정했습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;가장 유용한 변경이 먼저 나오고, 수정 항목은 앱이 종료되던 상황을 구체적으로 짚는다. 버전 번호도, &amp;quot;버그 수정 및 개선&amp;quot;도 없다. 스토어별 규칙은 &lt;a href=&quot;https://changeloop.dev/blog/ko/mobile-app-release-notes/&quot;&gt;모바일 앱 릴리스 노트&lt;/a&gt;에서 다룬다.&lt;/p&gt;
&lt;h2&gt;내부 릴리스 노트에는 무엇이 들어가야 하는가&lt;/h2&gt;
&lt;p&gt;내부 노트는 지원과 영업을 위한 버전이다. 공개 노트가 생략하는 것, 즉 무엇을 말해야 하고 무엇을 약속하지 말아야 하는지를 더한다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;다국어 청구서가 오늘 출시되었습니다(전 요금제).&lt;/strong&gt;
지원: 고객은 결제 환경설정에서 언어를 설정하며, 기존 청구서는 원래 언어를 유지합니다. 이탈리아어는 아직 지원되지 않습니다. 영업: 모든 요금제에서 열려 있으므로 업그레이드 상품으로 내세우지 마세요.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;각 대상이 자기 몫의 이름 붙은 줄을 받고, 고객이 묻기 전에 경계(&amp;quot;이탈리아어는 아직 지원되지 않습니다&amp;quot;)를 그어 둔다. 형식과 채널은 &lt;a href=&quot;https://changeloop.dev/blog/ko/internal-release-notes/&quot;&gt;내부용 릴리스 노트&lt;/a&gt; 글에서 다룬다.&lt;/p&gt;
&lt;h2&gt;나쁜 릴리스 노트는 어떻게 고쳐 쓰는가&lt;/h2&gt;
&lt;p&gt;나쁜 릴리스 노트는 독자가 얻는 것이 아니라 팀이 한 일을 나열한다. 결과를 앞으로 옮기고 내부 용어를 지우면 고칠 수 있다.&lt;/p&gt;
&lt;p&gt;이전:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;v3.8.1&lt;/strong&gt; 알림 스케줄러를 리팩터링했습니다. &lt;code&gt;ReminderJob&lt;/code&gt;의 race condition을 수정했습니다. &lt;code&gt;bull&lt;/code&gt;을 4.12로 업데이트했습니다. 기타 개선.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이후:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;알림 메일이 더 이상 두 번 나가지 않습니다.&lt;/strong&gt;
마감일이 월말인 청구서를 가진 고객이 알림을 두 번 받을 수 있었습니다. 이 문제는 수정되었고, 이미 발송된 알림을 다시 보낼 필요는 없습니다. 조치가 필요 없습니다.&lt;/p&gt;
&lt;p&gt;3.8.1의 다른 변경 사항: &lt;code&gt;bull&lt;/code&gt;을 4.12로 업데이트.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;의존성 업데이트는 하단의 한 줄로 내려갔고, race condition은 고객이 알아볼 수 있는 증상이 되었다.&lt;/p&gt;
&lt;h2&gt;릴리스마다 릴리스 노트를 일관되게 유지하려면&lt;/h2&gt;
&lt;p&gt;변경이 병합될 때 항목마다 초안을 쓰고, 출시하기 전에 사람이 승인하게 하라.&lt;/p&gt;
&lt;p&gt;Changeloop도 이렇게 동작한다. 병합된 pull request마다 AI로 항목의 초안을 만들고, 사람이 승인할 때까지 보류해 둔다. 승인 단계가 바로 편집자가 위의 규칙을 적용하는 자리다. 형식을 먼저 정하고 싶다면 &lt;a href=&quot;https://changeloop.dev/release-notes-template&quot;&gt;릴리스 노트 템플릿&lt;/a&gt;에서 시작하고, 완성된 페이지가 어떤 모습인지는 &lt;a href=&quot;https://changeloop.dev/changelog-examples&quot;&gt;체인지로그 예시&lt;/a&gt;를 보라.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;새 릴리스 노트란 무엇인가?&lt;/strong&gt;
새 릴리스 노트는 제품의 최신 릴리스와 함께 발행되는 메시지로, 무엇이 바뀌었고 사용자가 무엇을 해야 하는지 설명한다. 기능, 개선, 수정, 파괴적 변경을 다룬다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;릴리스 노트와 체인지로그의 차이는 무엇인가?&lt;/strong&gt;
체인지로그는 전체 이력을 원하는 누구나 볼 수 있게 모든 것을 담는다. 릴리스 노트는 거기서 골라 쓴다. 릴리스 하나에 대해, 그것이 자신에게 중요한지 판단하려는 독자를 위해 쓴다. 더 자세한 비교는 &lt;a href=&quot;https://changeloop.dev/blog/ko/changelog-vs-release-notes/&quot;&gt;체인지로그 대 릴리스 노트&lt;/a&gt;에 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;릴리스 노트는 무슨 뜻인가?&lt;/strong&gt;
릴리스 노트는 릴리스에서 무엇이 바뀌었는지 사용자에게 알려준다. 앱스토어의 &amp;quot;새로운 기능&amp;quot; 문구부터 회사 웹사이트의 한 페이지까지, 무엇이 출시되었는지 설명하는 모든 것을 가리킨다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;릴리스 노트 항목 하나는 얼마나 길어야 하는가?&lt;/strong&gt;
대부분의 항목은 두세 문장에서 네 문장이면 충분하다. 결과, 영향받는 대상, 해야 할 일이다. 파괴적 변경이나 보안 수정은 날짜나 마이그레이션이 필요하므로 더 길어질 수 있다.&lt;/p&gt;
</content:encoded></item><item><title>Stripe API 버전 관리, 작동 방식과 따라 할 점</title><link>https://changeloop.dev/blog/ko/stripe-api-versioning/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/stripe-api-versioning/</guid><description>Stripe API 버전 관리는 계정마다 날짜 기반 버전을 고정하고 요청마다 헤더로 덮어쓸 수 있게 한다. 작동 방식과 유지 비용, 작은 API가 따라 할 점을 설명한다.</description><pubDate>Fri, 02 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Stripe API 버전 관리는 날짜로 이루어진다. 모든 계정은 릴리스 날짜를 딴 API 버전에 고정되며, 개별 요청은 &lt;code&gt;Stripe-Version&lt;/code&gt; 헤더로 그 고정을 덮어쓸 수 있다. 이 글을 쓰는 시점(2026년 10월)에 Stripe 문서의 현재 버전은 &lt;code&gt;2026-09-30.endive&lt;/code&gt;이며, 훨씬 작은 API도 주말 하루면 같은 방식을 따라 할 수 있다.&lt;/p&gt;
&lt;p&gt;아래의 모든 Stripe 관련 사실은 Stripe 자체 페이지에서 가져왔으며, 사용한 자리에 링크를 달았다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;메커니즘&lt;/th&gt;
&lt;th&gt;Stripe의 방식&lt;/th&gt;
&lt;th&gt;출처&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;버전 이름&lt;/td&gt;
&lt;td&gt;날짜, 그리고 2024년부터는 릴리스 이름 (&lt;code&gt;2026-09-30.endive&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://docs.stripe.com/api/versioning&quot;&gt;Versioning&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;기본 버전&lt;/td&gt;
&lt;td&gt;계정에 고정되며 Workbench에서 변경&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://docs.stripe.com/api/versioning&quot;&gt;Versioning&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;요청별 덮어쓰기&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Stripe-Version&lt;/code&gt; 헤더 또는 SDK 옵션&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://docs.stripe.com/upgrades&quot;&gt;Upgrades&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;웹훅&lt;/td&gt;
&lt;td&gt;엔드포인트에 설정된 버전으로 렌더링&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://docs.stripe.com/upgrades&quot;&gt;Upgrades&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;주기&lt;/td&gt;
&lt;td&gt;파괴적 변경이 없는 월간 릴리스, 연 두 번의 메이저 릴리스&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://docs.stripe.com/api/versioning&quot;&gt;Versioning&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;오래된 버전&lt;/td&gt;
&lt;td&gt;내부 버전 변경 모듈로 계속 작동&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://stripe.com/blog/api-versioning&quot;&gt;Engineering post&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Stripe API 버전 관리는 어떻게 작동하는가&lt;/h2&gt;
&lt;p&gt;Stripe는 모든 계정에 기본 API 버전을 부여하고, 버전을 지정하지 않은 모든 요청은 그 버전을 쓴다. 호출하는 쪽은 기본값을 바꾸거나 개별 요청에 버전을 지정하는 방식으로 언제 옮길지 스스로 선택한다.&lt;/p&gt;
&lt;p&gt;Stripe의 엔지니어링 글에 따르면 계정은 처음 API 요청을 보낼 때 고정된다. 계정은 &amp;quot;automatically pinned to the most recent version available&amp;quot;가 되고, 그 이후의 모든 호출에는 그 버전이 암묵적으로 할당된다.&lt;/p&gt;
&lt;p&gt;버전 문자열은 날짜다. &lt;code&gt;2024-09-30.acacia&lt;/code&gt; 릴리스부터는 &lt;code&gt;2026-09-30.endive&lt;/code&gt;처럼 이름도 함께 붙는다. 날짜는 버전의 순서를 정하고, 이름은 그 버전이 어느 메이저 릴리스 계열에 속하는지 알려준다.&lt;/p&gt;
&lt;h2&gt;요청마다 버전은 어떻게 선택하는가&lt;/h2&gt;
&lt;p&gt;요청에 &lt;code&gt;Stripe-Version&lt;/code&gt; 헤더를 보내거나 SDK에서 버전을 설정한다. Stripe의 업그레이드 가이드가 헤더 형태를 보여주며, 같은 호출이 라이브 환경과 테스트 환경 모두에서 작동한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;curl https://api.stripe.com/v1/charges \
  -u &amp;quot;$STRIPE_SECRET_KEY:&amp;quot; \
  -H &amp;quot;Stripe-Version: 2026-09-30.endive&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Stripe의 가이드에 따르면 SDK에서 버전을 전역으로 또는 요청마다 설정하면 응답 객체도 그 버전으로 돌아온다.&lt;/p&gt;
&lt;p&gt;Stripe는 계정 기본값에 기대지 말라고도 권한다. 요청마다 헤더나 고정된 SDK로 버전을 지정해서, 대시보드 설정이 아니라 여러분의 코드가 버전을 결정하게 하라는 것이다.&lt;/p&gt;
&lt;p&gt;SDK는 언어에 따라 고정 방식이 다르다. 문서에 따르면 동적 타입 라이브러리의 최신 버전은 해당 SDK 릴리스가 나왔을 때의 최신 API 버전을 쓰고, 강한 타입을 쓰는 라이브러리(Java, Go, .NET)는 그 버전에 고정된다. 라이브러리 버전을 설치하는 것이 사실상 API 버전을 선택하는 일이다.&lt;/p&gt;
&lt;h2&gt;버전이 바뀌면 웹훅은 어떻게 되는가&lt;/h2&gt;
&lt;p&gt;웹훅 이벤트는 서버 코드가 쓰는 버전이 아니라 그 엔드포인트에 연결된 API 버전으로 렌더링된다. Stripe 문서에 따르면 이벤트는 엔드포인트를 만들 때 설정한 버전을 쓰고, 설정하지 않았다면 계정 기본값을 쓴다. SDK 버전을 바꿔도 웹훅 핸들러가 받는 내용은 바뀌지 않는다.&lt;/p&gt;
&lt;p&gt;그래서 요청 경로와 이벤트 경로가 서로 다른 두 버전에 놓일 수 있다. 이벤트 대상의 경우 &lt;code&gt;snapshot_api_version&lt;/code&gt;은 대상을 만들 때만 설정하므로, 다른 버전을 쓰려면 새 대상을 만들어야 한다.&lt;/p&gt;
&lt;p&gt;이에 대한 Stripe의 업그레이드 경로는 병렬 실행이다. 목표 버전으로 새 엔드포인트를 만들고, 같은 이벤트를 양쪽에 보내고, 핸들러가 한쪽은 처리하고 다른 쪽은 무시하도록 가르친 다음, 전환하고 기존 엔드포인트를 비활성화한다. 겹치는 동안 모든 이벤트가 두 번 도착하므로 핸들러는 멱등해야 한다. 이벤트를 내보내는 어떤 API에도 따라 할 만한 좋은 패턴이며, 이런 방식이 필요해지는 페이로드 변경은 &lt;a href=&quot;https://changeloop.dev/blog/ko/webhook-changelog/&quot;&gt;웹훅 체인지로그&lt;/a&gt;에서 공지한다.&lt;/p&gt;
&lt;h2&gt;월간 릴리스와 메이저 릴리스는 무엇인가&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;2024-09-30.acacia&lt;/code&gt; 릴리스부터 Stripe는 파괴적 변경 없이 매달 새 API 버전을 내놓고, 연 두 번 파괴적 변경이 담긴 버전으로 시작하는 새 메이저 릴리스를 낸다. 버전 관리 페이지에 따르면 코드를 업데이트하지 않고도 어떤 월간 릴리스로든 업그레이드할 수 있지만, 메이저 릴리스는 변경이 필요할 수 있다.&lt;/p&gt;
&lt;p&gt;메이저 릴리스에는 이름이 붙는다. 버전 관리 페이지는 Basil을 예로 들고, 이 절차에 대한 Stripe의 발표는 이름이 식물에서 왔고 Acacia로 시작하며, 월간 릴리스는 바로 앞 메이저 릴리스의 이름을 유지해서 그 이름이 안전하게 올려도 된다는 신호가 된다고 밝힌다. Stripe의 &lt;a href=&quot;https://docs.stripe.com/changelog&quot;&gt;changelog&lt;/a&gt;에 사용 중인 이름들이 나열되어 있고, 이 글을 쓰는 시점에 가장 최신 항목은 &lt;code&gt;2026-09-30.endive&lt;/code&gt;이다.&lt;/p&gt;
&lt;p&gt;그래서 날짜는 &amp;quot;얼마나 새로운가&amp;quot;에 답하고, 이름은 &amp;quot;파괴적 경계인가&amp;quot;에 답한다. Stripe의 발표는 예외의 여지도 남겨 둔다. 그렇게 하지 않으면 통합이 심각한 영향을 받을 상황에서는 주기를 벗어난 파괴적 변경을 낼 권리를 보유한다. 이 발표는 &lt;a href=&quot;https://stripe.com/blog/introducing-stripes-new-api-release-process&quot;&gt;Stripe&amp;#39;s new API release process&lt;/a&gt;에 있다.&lt;/p&gt;
&lt;h2&gt;Stripe API의 최신 버전은 무엇인가&lt;/h2&gt;
&lt;p&gt;이 글을 쓰는 시점(2026년 10월)에 Stripe의 버전 관리 페이지는 현재 버전이 &lt;code&gt;2026-09-30.endive&lt;/code&gt;라고 밝히고, changelog도 같은 버전을 가장 최신으로 나열한다. Stripe는 매달 새 버전을 내므로 글에 인쇄된 문자열은 금세 낡는다. 무언가를 고정하기 전에 실시간 changelog를 읽고, 테스트한 버전으로 고정하라.&lt;/p&gt;
&lt;h2&gt;Stripe는 오래된 버전을 어떻게 계속 작동하게 하는가&lt;/h2&gt;
&lt;p&gt;Stripe는 모든 파괴적 변경을 독립적인 버전 변경 모듈로 작성하고, 데이터의 가장 최신 형태에서부터 거꾸로 그 모듈들을 적용하는 방식으로 오래된 버전을 살려 둔다. 그 메커니즘은 &lt;a href=&quot;https://stripe.com/blog/api-versioning&quot;&gt;API 버전 관리에 대한 엔지니어링 글&lt;/a&gt;에 설명되어 있다.&lt;/p&gt;
&lt;p&gt;각 모듈은 무엇을 바꾸는지 선언하고, 변경을 문서화하고, 변환 함수를 포함한다. 이 글은 필드가 문자열에서 해시로 바뀌는 예를 든다. 응답을 만들 때 시스템은 목표 버전을 알아낸 뒤, 시간을 거슬러 올라가며 그 버전에 이를 때까지 도중에 만나는 모듈을 하나씩 적용한다.&lt;/p&gt;
&lt;p&gt;이 설계에서 두 가지 부수 효과가 따라오며, 글은 둘 다 짚는다. 모듈이 자신이 건드리는 필드와 리소스를 선언하므로 Stripe는 배포할 때 이 모듈들로 API changelog를 생성할 수 있다. 그리고 계정의 버전을 알고 있으므로 문서가 그 버전에 맞춰지고, 그 버전 이후의 하위 호환되지 않는 변경에 대해 경고할 수 있다.&lt;/p&gt;
&lt;h2&gt;비용은 얼마이며 작은 API는 무엇을 따라 해야 하는가&lt;/h2&gt;
&lt;p&gt;버전 관리에는 엔지니어링의 주의력이 들고, Stripe도 그렇게 말한다. 엔지니어링 글은 유지 보수 부담을 인정하며, 새 코드를 작성하면서 옛 동작에 대해 생각할 일이 적을수록 좋다는 목표를 밝힌다. 또한 버전 변경이 아예 필요하지 않도록 릴리스 전에 가벼운 API 검토를 거친다고 설명한다.&lt;/p&gt;
&lt;p&gt;작은 API는 오래된 버전마다 모듈 사슬을 감당할 수 없고, 그럴 필요도 없다. 가치를 담은 부분만 따라 하라.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;날짜 기반 버전.&lt;/strong&gt; 날짜는 무엇이 &amp;quot;메이저&amp;quot;인지 판단할 필요가 없고, 호출하는 쪽이 읽을 수 있다. &lt;a href=&quot;https://changeloop.dev/blog/ko/api-versioning-best-practices/&quot;&gt;API 버전 관리 모범 사례&lt;/a&gt; 글은 이것을 URL 방식, 헤더 방식과 비교한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;고정된 기본값.&lt;/strong&gt; 처음 사용할 때 계정이나 키를 그 버전에 고정해서, 작동 중인 통합 아래에서 API가 바뀌는 일이 없게 한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;요청별 덮어쓰기.&lt;/strong&gt; 호출하는 쪽이 확정하기 전에 프로덕션에서 호출 한 건으로 새 버전을 시험해 볼 수 있게 하는 헤더.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;웹훅 엔드포인트의 버전.&lt;/strong&gt; 이벤트 페이로드가 호출하는 쪽이 가장 자주 놀라는 곳이다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;버전마다 체인지로그 항목 하나.&lt;/strong&gt; 버전, 날짜, 영향받는 대상, 해야 할 일을 밝힌다. &lt;a href=&quot;https://changeloop.dev/blog/ko/breaking-changes/&quot;&gt;무엇이 파괴적 변경인가&lt;/a&gt;는 새 버전에 무엇이 속하는지 가리는 기준이고, &lt;a href=&quot;https://changeloop.dev/blog/ko/api-changelog/&quot;&gt;API 체인지로그&lt;/a&gt; 글은 항목 자체를 다룬다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;지원하는 버전의 수 때문에 어쩔 수 없게 될 때까지는 모듈 사슬을 건너뛰어라. 운영 중인 버전이 두세 개라면 몇 개의 분기와 종료일로 감당할 수 있으며, &lt;a href=&quot;https://changeloop.dev/blog/ko/sunsetting-api-version/&quot;&gt;API 버전 종료&lt;/a&gt;가 그 과정을 안내한다.&lt;/p&gt;
&lt;p&gt;날짜가 있는 체인지로그를 발행한다면, 버전 이력은 그 항목들만큼만 좋다. &lt;a href=&quot;https://changeloop.dev/docs&quot;&gt;Changeloop&lt;/a&gt;에서는 병합된 pull request마다 항목 초안이 만들어지고, 체인지로그 페이지와 피드에 발행되기 전에 사람이 승인하도록 보류된다. 버전별 항목이 작성되는 자리가 바로 거기이며, 사람이 거치는 한 번의 관문이 호출하는 쪽이 무엇을 해야 하는지를 말해 주는 검토다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Stripe API의 최신 버전은 무엇인가?&lt;/strong&gt;
이 글을 쓰는 시점(2026년 10월)에 Stripe의 버전 관리 페이지는 현재 버전이 &lt;code&gt;2026-09-30.endive&lt;/code&gt;라고 밝힌다. Stripe는 매달 새 버전을 내므로 고정하기 전에 changelog를 확인하고, 계정 기본값에 기대는 대신 버전을 코드에 적어 두라.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;요청에 Stripe API 버전은 어떻게 설정하는가?&lt;/strong&gt;
&lt;code&gt;Stripe-Version: 2026-09-30.endive&lt;/code&gt;처럼 &lt;code&gt;Stripe-Version&lt;/code&gt; 헤더를 보내거나, 서버 쪽 SDK에서 버전을 전역으로 또는 요청마다 설정한다. 둘 다 없으면 요청은 계정의 기본 버전을 쓰며, 이는 Workbench에서 직접 설정한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;웹훅은 내 요청과 같은 Stripe API 버전을 쓰는가?&lt;/strong&gt;
꼭 그렇지는 않다. 웹훅 이벤트는 엔드포인트를 만들 때 설정한 버전을 쓰고, 설정하지 않았다면 계정 기본값을 쓴다. SDK를 업그레이드해도 웹훅 핸들러가 받는 페이로드는 바뀌지 않으므로, 엔드포인트는 따로 업그레이드하고 병렬로 테스트하라.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stripe식 날짜 버전 관리는 작은 API에 맞는가?&lt;/strong&gt;
날짜 버전, 고정된 기본값, 요청별 헤더, 버전마다 체인지로그 항목 하나는 비용이 적게 들고 따라 할 가치가 있다. 오래된 버전을 한꺼번에 많이 지원하게 되기 전까지는 내부의 버전 변경 모듈 사슬은 그렇지 않다. 운영 중인 버전 두 개와 오래된 쪽의 종료일부터 시작하라.&lt;/p&gt;
</content:encoded></item><item><title>체인지로그는 누가 쓰는가, 그리고 누가 써야 하는가</title><link>https://changeloop.dev/blog/ko/changelog-entry-ownership/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/changelog-entry-ownership/</guid><description>체인지로그는 누가 쓰는가? PR 작성자는 무엇이 바뀌었는지 알고 PM은 왜 중요한지 안다. 어느 쪽도 혼자서는 쓸모 있는 항목을 쓸 수 없다.</description><pubDate>Tue, 22 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;팀에게 누가 체인지로그를 쓰냐고 물으면 정직한 대답은 대개 &amp;quot;기억하는 사람 아무나&amp;quot;이며, 이것은
&lt;a href=&quot;https://changeloop.dev/blog/ko/changelog-ci-enforcement/&quot;&gt;CI에서 체인지로그 항목을 강제하기&lt;/a&gt;가 기계적인 수준에서
고치려는 것과 똑같은 실패 방식이다. 하지만 항목이 존재하도록 강제하는 것이 누가 좋은 항목을
쓸 자격이 있는지를 결정해주지는 않으며, 그 질문을 건너뛰는 팀들은 대개 강제하기 가장 쉬운
사람, 보통 PR 작성자에게 기본값으로 넘기면서 그 사람이 정말 그것을 잘 쓸 수 있는 사람인지는
확인하지 않는다.&lt;/p&gt;
&lt;h2&gt;PR 작성자가 자동으로 최고의 체인지로그 작성자가 되지 않는 이유는 무엇인가&lt;/h2&gt;
&lt;p&gt;그녀는 구현을 알지만 반드시 영향을 아는 것은 아니고, 이것은 서로 다른 종류의 지식이기
때문이다. &lt;a href=&quot;https://changeloop.dev/blog/ko/conventional-commits-changelog/&quot;&gt;Conventional commits는 어디서 멈추는가&lt;/a&gt;는
이 간극을 커밋 메시지 쪽에서 다룬다. &lt;code&gt;fix(auth): reject expired refresh tokens&lt;/code&gt;는 정확하지만
고객에게는 아무것도 말해주지 않으며, 그 수정을 쓴 사람은 종종 그것을 번역하기에 가장 부적합한
사람이다. 몇 시간 동안 그 버그의 관점에서 생각하느라 사용자가 실제로 무엇을 경험했는지에
대한 외부 시각을 잃어버렸기 때문이다. 이것이 테크니컬 라이터라는 직업이 존재하는 것과 같은 이유다. 구현을 영향으로 번역하는 것은
그것을 만드는 것과는 별개의 기술이며, 그 코드를 얼마나 잘 다루는 개발자든 상관없이 연습이
필요하다.&lt;/p&gt;
&lt;h2&gt;그렇다면 제품팀이나 지원팀이 대신 모든 항목을 써야 한다는 뜻인가&lt;/h2&gt;
&lt;p&gt;아니다, 그들은 정반대의 간극을 갖고 있기 때문이다. 사용자에게 무엇이 중요한지는 알지만
실제로 무엇이 출시되었는지는 항상 아는 것이 아니며, 이는 읽기는 쉽지만 때로 범위가 틀린
항목을 만들어낸다. 여전히 플래그 뒤에 있는 기능에 대해 &amp;quot;이제 X를 지원합니다&amp;quot;라는 주장,
혹은 세 가지 경우 중 하나만 다루면서 완료된 것으로 서술된 수정이 그렇다. 개발자가 쓴
항목의 실패 방식은 읽기 어렵지만 정확한 것이고, PM이 쓴 항목의 실패 방식은 읽기 쉽지만
검증되지 않은 것이다. 어느 역할도 좋은 항목에 필요한 것의 양쪽 절반을 모두 소유하고
있지 않다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;역할&lt;/th&gt;
&lt;th&gt;대개 잘 맞히는 것&lt;/th&gt;
&lt;th&gt;대개 틀리는 것&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;코드를 쓴 개발자&lt;/td&gt;
&lt;td&gt;무엇이 바뀌었는지의 정확한 범위&lt;/td&gt;
&lt;td&gt;그것을 만들지 않은 사람을 위한 틀 잡기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PM 또는 지원 리드&lt;/td&gt;
&lt;td&gt;사용자에게 왜 중요한지&lt;/td&gt;
&lt;td&gt;실제로 출시된 것의 정확한 경계&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;전담 체인지로그 소유자&lt;/td&gt;
&lt;td&gt;일관된 목소리, 범위를 대조함&lt;/td&gt;
&lt;td&gt;대조할 수 있으려면 위 두 가지가 모두 필요함&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;실제로 작동하는 소유권 모델은 어떤 모습인가&lt;/h2&gt;
&lt;p&gt;변경 사항에 가장 가까운 사람이 초안을 쓰고, 사용자에게 가장 가까운 사람이 검토하며, 모두가
다른 누군가가 문제를 잡아줄 거라고 가정하는 대신 한 명의 지정된 사람이 최종 문구에 책임을
지는 것이다. 초안은 훌륭할 필요보다 존재하고 정확할 필요가 더 크다. 개발자가 쓴, 무엇이
바뀌었는지를 정확히 말하는 거친 문장이 다듬어졌지만 검증되지 않은 것보다 더 나은 출발점이다.
명료함을 위해 다시 쓰는 것이 정확함을 위해 다시 쓰는 것보다 쉽기 때문이다. 검토 단계는 PM
또는 지원 리드가 초안을 읽고 가독성의 간극을 잡아내는 하나의 질문을 던지는 곳이다: 코드를
보지 않았어도 이것을 이해했을까.&lt;/p&gt;
&lt;h2&gt;항상 같은 사람이 책임져야 하는가, 아니면 순환해야 하는가&lt;/h2&gt;
&lt;p&gt;지정되고 안정적인 것이 순환하는 것을 이긴다, 적어도 최종 승인에 대해서는. 순환하는 소유자는
매번 팀의 관례를 처음부터 다시 유추하는 누군가가 각 항목을 검토한다는 것을 의미하며, 이는
정확히 목소리가 항목마다 표류하고 독자가 체인지로그가 위원회에 의해 쓰였다는 것을 알아차리기
시작하는 방식이다. 한 사람, 또는 매우 작고 안정적인 그룹은 시간이 지나면서 판단을 축적한다.
언제 &amp;quot;개선했습니다&amp;quot;라고 말하고 언제 구체적인 숫자를 언급할지, 언제 수정이 자기 항목을
필요로 하고 언제 배치에 묶어 넣을지. 그 판단은 작업을 균등하게 분배하는 것보다 더 가치가
있다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;초안 (개발자, PR에서):
&amp;quot;Fixed pagination cursor not respecting the `sort` param
in some edge cases.&amp;quot;

검토됨 (체인지로그 소유자, 실제 PR과 대조함):
&amp;quot;수정됨: 날짜순으로 정렬된 내보내기가 첫 페이지를
넘어가면 순서가 뒤바뀐 결과를 반환할 수 있었습니다.
이제 모든 페이지에서 일관됩니다.&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;작은 팀은 한 줄의 텍스트를 위해 이렇게 많은 과정이 필요한가&lt;/h2&gt;
&lt;p&gt;별개의 사람으로서의 역할은 아니지만, 그 두 단계는 혼자서도 여전히 중요하다. 한 사람으로
이루어진 팀은 개발자이자 검토자이며, 그 규모에서 살아남는 규율은 검토를 별도의 정신적
단계로 수행하는 것이지, 수정을 쓰는 것에서 그 설명을 발행하는 것으로 한 호흡에 바로
건너뛰지 않는 것이다. 작은 규모의 함정은 두 번째 단계를 완전히 건너뛰는 것이지, 두 번째 사람이 없다는 것이 아니다.
외부의 아무도 그것을 강제하지 않기 때문이며, 그 단계가 잡아내기
위해 존재하는 정확성의 간극은 같은 사람이 이론적으로 자기 사각지대를 알아차릴 수 있다는
이유만으로 사라지지 않는다.&lt;/p&gt;
&lt;h2&gt;최종 항목에 아무도 책임지지 않으면 어떻게 되는가&lt;/h2&gt;
&lt;p&gt;체인지로그는 완전히 실패하는 대신 고르지 못하게 저하된다, 이것이 더 나쁜 이유는 독자가
지적할 때까지 아무도 알아차리지 못하기 때문이다. 어떤 항목은 그것을 쓴 사람이 신경 썼기
때문에 예리하게 남아 있고, 다른 항목은 그것을 쓴 사람이 빨리 움직였고 발행 전에 아무도
잡아내지 못했기 때문에 &amp;quot;다양한 개선 사항 및 버그 수정&amp;quot;처럼 모호해진다. &lt;a href=&quot;https://changeloop.dev/blog/ko/keep-a-changelog-implemented/&quot;&gt;Keep a
Changelog&lt;/a&gt;의 형식 제약은 구조적 표류, 빠진 날짜,
잘못된 범주를 잡아내지만, 템플릿 안의 그 어떤 것도 기술적으로는 올바르게 형식이 갖춰진
모호한 항목을 잡아내지 못한다. 이것이 정확히 지정된 소유자가 메우기 위해 존재하는 간극이다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;체인지로그 소유자는 엔지니어링 역할이어야 하는가, 제품 역할이어야 하는가?&lt;/strong&gt;
둘 다 그 사람이 범위를 검증할 기술적 유창함과 외부 독자를 위해 쓸 만큼 구현으로부터의
충분한 거리를 모두 갖고 있다면 작동할 수 있다. 직함은 두 절반을 모두 해낼 수 있는지, 혹은
자신이 할 수 없는 절반에 대해 누구에게 물어봐야 할지 아는지보다 덜 중요하다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;온콜 같은 순환 일정이 체인지로그 소유권에 적합한 경우가 있는가?&lt;/strong&gt;
분량에 대해서는 가끔, 팀이 너무 작아서 한 사람이 모든 것을 검토할 수 없다면 그렇다. 목소리와
판단에 대해서는 아니다, 그것이 정확히 순환이 침식시키는 것이기 때문이다. 안정적인 검토자
한 명을 유지하면서 초안 작성의 부담을 나누는 순환은 표류 없이 그 이점을 얻는다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;현재의 소유권 설정에 뭔가 잘못되었다는 가장 빠른 신호는 무엇인가?&lt;/strong&gt;
정확하지만 읽기 어려운 항목, 혹은 읽기 쉽지만 범위가 틀린 항목이 누가 썼는지를 따르는
패턴으로 나타나는 것이다. 품질이 일관되게 유지되는 대신 작성자와 상관관계를 보인다면,
간극은 소유권에 있는 것이지 글쓰기 능력에 있는 것이 아니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;자동화는 소유권이 얼마나 중요한지를 줄이는가?&lt;/strong&gt;
필요한 글쓰기의 양을 줄이는 것이지, 필요한 판단의 양을 줄이는 것이 아니다.
&lt;a href=&quot;https://changeloop.dev/blog/ko/changelog-automation/&quot;&gt;체인지로그 자동화&lt;/a&gt;는 파이프라인이 안전하게 생성할 수
있는 것, 형식화, 발행, 크로스포스팅을 다룬다. 문구, 그룹화, 그리고 무엇이 언급할 가치가
있는지는 파이프라인의 얼마나 많은 부분이 자동화되었든 상관없이 인간의 결정으로 남는다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PR 작성자와 검토자가 문구를 두고 의견이 갈리면 어떻게 하는가?&lt;/strong&gt;
검토자의 판단을 따른다. 그들이 답하고 있는 질문, 즉 외부 독자가 이것을 이해할까라는 질문이
바로 그 역할이 지키기 위해 존재하는 것이기 때문이다. 그렇다고 개발자의 판단이 무가치하다는
뜻은 아니다. 의견 차이가 문구가 아니라 정확성에 관한 것이라면 검토자가 물러선다. 범위를
올바르게 맞추는 것은 작성자의 몫이기 때문이다. 문구와 정확성이라는 두 종류의 의견 차이를
구분하는 것만으로 이런 상황 대부분이 교착 상태로 번지는 것을 막을 수 있다.&lt;/p&gt;
</content:encoded></item><item><title>긴급 릴리스 노트: 실시간 시간 압박 속에서 쓰기</title><link>https://changeloop.dev/blog/ko/emergency-release-notes/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/emergency-release-notes/</guid><description>인시던트로 시작된 긴급 릴리스는 며칠이 아니라 몇 분 안에 노트가 필요하다. 평소의 작성 과정은 없는 시간을 전제로 하므로 무엇을 남기고 자를지 설명한다.</description><pubDate>Tue, 22 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;대부분의 릴리스 노트는 코드가 완성된 후에 쓰이고, 여유롭게 검토되며, 누군가 그것을 얼마나
긴급하게 읽어야 하는지와는 무관한 일정에 따라 발행된다. 긴급 릴리스, 보안 패치, 데이터
손실 버그, 장애 수정은 이 모든 조건을 한꺼번에 뒤집는다. 노트는 대부분의 사람들이 평소
쓰기 시작할 시점보다 먼저 존재해야 하고, 검토를 거의 받지 못하며, 여유로운 독자가 아니라
불안한 독자가 읽는다. &lt;a href=&quot;https://changeloop.dev/blog/ko/how-to-write-release-notes/&quot;&gt;릴리스 노트 쓰는 법&lt;/a&gt;은 평소
과정을 다룬다. 이것은 그것을 따를 시간이 전혀 남지 않았을 때 무엇이 달라지는지에 관한
것이다.&lt;/p&gt;
&lt;h2&gt;그 무엇보다도 긴급 릴리스 노트가 반드시 제대로 해야 할 한 가지는 무엇인가&lt;/h2&gt;
&lt;p&gt;독자가 무언가를 해야 하는지 여부를, 그 앞에 아무런 프레이밍도 없이 첫 문장에서 말하는
것이다. 인시던트가 촉발한 노트를 접하는 독자는 상태 페이지, 지원 스레드, 혹은 자기 자신의
사용자들로부터 문제에 대해 들었기 때문에 이미 걱정하고 있는 경우가 많다. 행동 항목 앞에
맥락으로 시작하는 노트는, 정보를 보류하는 것이 가장 나쁘게 읽히는 바로 그 상황에서 정보를
보류하는 것처럼 읽힌다. &amp;quot;조치가 필요하지 않습니다, 이것은 악용에 사용자 데이터가 필요하지
않았던 취약점을 패치합니다&amp;quot;와 &amp;quot;지금 바로 업데이트하세요: 이 릴리스는 한 계정의 데이터를
다른 계정에 표시할 수 있었던 버그를 수정합니다&amp;quot;는 둘 다 한 문장이며, 둘 다 불안한 독자가
다른 어떤 것을 읽기 전에 필요로 하는 일을 전부 해낸다.&lt;/p&gt;
&lt;h2&gt;시간이 없을 때도 평소의 편집이 적용되는가&lt;/h2&gt;
&lt;p&gt;압축하려는 본능은 그것을 평소에 만들어내는 여러 초안 과정이 없어도 살아남는다.
&lt;a href=&quot;https://changeloop.dev/blog/ko/how-to-write-release-notes/&quot;&gt;다시 쓰기&lt;/a&gt;는 장황한 첫 초안을 그 핵심으로 깎아내는
것을 설명한다. 시간 압박 속에서는 깎아낼 첫 초안 자체가 없는 경우가 많은데, 이는 그 훈련이
나중의 별도 단계가 아니라 쓰는 도중 머릿속에서 작동해야 한다는 것을 의미한다. 가장 빠른
접근법: &amp;quot;제가 뭘 알아야 하나요&amp;quot;라고 묻는 사람에게 소리 내어 말할 문장을 쓰고 멈추는 것이다.
그 문장이 보통 만들어내기 가장 빠르면서도 그 상태의 독자가 실제로 처리할 유일한 것이기
때문이다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;평소 릴리스 노트&lt;/th&gt;
&lt;th&gt;긴급 릴리스 노트&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;코드 리뷰 후, 발행 전에 쓰인다&lt;/td&gt;
&lt;td&gt;흔히 수정과 동시에, 완전한 검토 전에 쓰인다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;여러 항목을 빠르게 훑도록 최적화된다&lt;/td&gt;
&lt;td&gt;스트레스 속에서 단독으로 읽히는 하나의 항목을 위해 최적화된다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;세부 사항을 연결된 체인지로그로 미룰 수 있다&lt;/td&gt;
&lt;td&gt;가장 중요한 사실을 가장 먼저 놓아야 한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;프레이밍과 맥락이 환영받는다&lt;/td&gt;
&lt;td&gt;행동 항목 앞의 프레이밍은 지연처럼 읽힌다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;문제의 원인을 정말로 확신하기 전에 노트를 발행해도 괜찮은 경우가 있는가&lt;/h2&gt;
&lt;p&gt;그렇다, 노트가 갖고 있지 않은 확신을 암시하는 대신 그 불확실성에 대해 정직하다면. &amp;quot;결제
과정에서 오류율이 상승한 것에 대한 수정을 배포했습니다. 근본 원인은 아직 확인 중이며 이
노트를 업데이트하겠습니다&amp;quot;는 방어 가능하고 올바르게 시간을 번다. 실제로 확인하지 않은
구체적인 원인을 주장하는 노트는, 그것이 틀린 것으로 판명될 경우 나중에 사람들이 당신에게
다시 인용할 종류의 추측이다. 여기서 중요한 훈련은 진단의 속도가 아니라, 노트의 확신이 팀의
실제 확신을 결코 넘어서지 않게 하는 것이다. 긴급 노트 안의 잘못된 기술적 주장은 인정된
무지보다 신뢰를 더 크게 훼손하기 때문이다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;지나치게 확신에 참, 검증되지 않음:
&amp;quot;Fixed: a race condition in the payment webhook handler
caused duplicate charges.&amp;quot;

시간 압박 속의 정직함:
&amp;quot;수정됨: 일부 고객이 하나의 주문에 대해 두 번
청구되었습니다. 새로운 발생을 중단했고, 영향을 받은
계정에는 24시간 이내에 환불했습니다. 근본 원인을
조사하고 있습니다.&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;긴급 노트는 문제의 원인을 언급해야 하는가, 아니면 수정되었다는 것만 말해야 하는가&lt;/h2&gt;
&lt;p&gt;무엇이 수정되었는지, 그리고 독자가 무엇을 해야 하는지를 말하라. 근본 원인은 추측이 아니라
실제로 밝혀졌을 때의 후속 조치를 위해 남겨두라. 인시던트 한가운데 있는 독자는 정확히 두
가지 사실을 원한다. 그것이 해결되었는가, 그리고 그것이 나에게 영향을 미치는가. 근본 원인에
대한 설명은, 정확하다 해도 그것을 잃어버리기 가장 나쁜 순간에 그 두 가지 사실과 주의를
놓고 경쟁한다. 사후 분석은 조사가 끝난 후 별도로 발행되는 것으로, 근본 원인이 속하는
곳이다. 시간 압박 속에서 두 문서를 섞으면 쓰기도 더디고 읽기도 더딘 노트가 만들어지는데,
그것은 긴급 상황이 필요로 하는 것의 정반대다.&lt;/p&gt;
&lt;h2&gt;모바일 앱의 강제 업데이트 문제도 여기 적용되는가&lt;/h2&gt;
&lt;p&gt;같은 원칙이 더욱 압축된 형태로 적용된다. &lt;a href=&quot;https://changeloop.dev/blog/ko/mobile-app-release-notes/&quot;&gt;모바일 앱 릴리스 노트&lt;/a&gt;는
강제 업데이트를 다루는데, 그곳에서는 노트가 다른 무엇보다 먼저 이유와 마감일을 말해야
한다. 독자가 선택권이 없다는 사실에 이미 짜증이 나 있기 때문이다. 웹의 긴급 노트는 보통
독자에게 그것에 따라 행동할지 선택한다는 의미에서 선택 사항이지만, 같은 &amp;quot;제약을 먼저
말하라&amp;quot;는 본능이 적용된다. 다만 이유가 다르다. 짜증이 아니라 긴급함이다.&lt;/p&gt;
&lt;h2&gt;그래서는 안 되는데도 긴급 노트가 잘못을 고백하는 것처럼 읽히지 않으려면 어떻게 해야 하는가&lt;/h2&gt;
&lt;p&gt;오류 자체가 아니라 수정과 그 효과를 설명하고, 과도하게 사과하고 싶은 충동을 억누르라. 그것은
위의 두 가지 사실을 원하는 독자에게 군더더기처럼 읽힌다. &amp;quot;일부 내보내기에 영향을 미친 버그를
찾아 수정했습니다&amp;quot;는 드라마를 더하지 않고 무슨 일이 일어났는지를 말한다. &amp;quot;저희의 소중한
고객님들께 영향을 드린 이 심각한 문제에 대해 진심으로 사과드립니다&amp;quot;는 독자가 요청하지 않은
감정적인 순간을 전달하기 위해 유용한 정보를 문장 하나만큼 지연시킨다. 간결하고 사실적인 노트는
차가운 것이 아니라, 독자의 실제 상태에 대한 존중이다. 진짜 압박 속에서 그것은 위로에 대한
필요가 아니라 조급함이기 때문이다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;긴급 릴리스 노트도 평소 노트와 같은 검토 과정을 거쳐야 하는가?&lt;/strong&gt;
더 가벼운 형태로, 아예 없는 것은 아니다. 노트가 확신을 과장하지 않았는지 확인하는 한 명의
빠른 검토자는 그것이 필요로 하는 몇 분의 가치가 있다. 검토되지 않은 기술적 주장이 틀릴
위험은, 바로 그것이 빠르게 쓰였기 때문에 더 높기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;추가 세부 사항으로의 링크 없이 긴급 노트를 발행해도 괜찮은가?&lt;/strong&gt;
잠깐 동안만. 링크 없는 노트는 처음 발행되는 것으로는 괜찮다. 상태 페이지나 후속 노트로의
링크를 그중 하나가 생기는 즉시 추가하라. 당신이 준 그 한 문장 이상을 원하는 독자는 갈 곳이
필요하기 때문이다. 설령 그곳이 &amp;quot;추가 세부 사항은 곧 제공됩니다&amp;quot;라고 말할 뿐이라 해도.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;긴급 노트를 완전히 생략하고 수정 사항을 조용히 내보내도 되는 경우가 있는가?&lt;/strong&gt;
어떤 독자도 알아차리거나 영향을 받을 수 없는 문제에 대해서만이다. 독자가 그 문제를 경험했을
가능성이 있다면, 노트는 그것이 끝났다는 것을 알려주는 것이며, 침묵은 그 문제가 여전히
활성 상태일지도 모른다는 것처럼 읽힌다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;인시던트가 해결된 후 긴급 노트는 얼마나 오래 고정되거나 눈에 띄게 남아 있어야 하는가?&lt;/strong&gt;
즉각적인 불안의 창이 닫힐 때까지, 보통 하루나 이틀이며, 그 후에는 다른 어떤 항목과도
마찬가지로 평소 체인지로그에 접혀 들어갈 수 있다. 몇 주 동안 고정된 채로 남아 있는 노트는
해결된 우려가 아니라 해결되지 않은 우려처럼 읽히기 시작한다.&lt;/p&gt;
</content:encoded></item><item><title>Protobuf 브레이킹 체인지: 와이어에서 살아남는 것</title><link>https://changeloop.dev/blog/ko/grpc-protobuf-api-changes/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/grpc-protobuf-api-changes/</guid><description>Protobuf 파괴적 변경은 URL이 아니라 와이어 위에서 일어난다. 어떤 gRPC 필드 변경은 공짜지만 다른 변경은 모든 클라이언트를 조용히 망가뜨린다.</description><pubDate>Tue, 22 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;REST API는 JSON의 형태가 바뀔 때 바뀌고, 그 형태의 대부분은 브라우저에서 읽을 수 있는 응답 안에
보인다. gRPC API는 &lt;code&gt;.proto&lt;/code&gt; 파일이 바뀔 때 바뀌며, Protocol Buffers의 바이너리 와이어 포맷은
필드 이름이 뭐라고 말하든 상관없이 클라이언트가 견딜 수 있는 것에 대해 자기만의 규칙을 갖는다.
diff에서 똑같이 사소해 보이는 두 변경, 필드 번호를 다시 매기는 것과 새 필드를 추가하는 것은,
&lt;a href=&quot;https://changeloop.dev/blog/ko/breaking-changes/&quot;&gt;breaking changes&lt;/a&gt;가 일반적으로 긋는 선의 반대편에 떨어진다. 하나는
기존 클라이언트 모두에게 보이지 않고, 다른 하나는 그것들 전부를 한꺼번에 망가뜨린다. protobuf
브레이킹 체인지를 안전한 변경과 구별한다는 것은 &lt;code&gt;.proto&lt;/code&gt; diff가 어떻게 읽히는지 짐작하는 게
아니라 와이어 포맷 자체의 규칙을 읽는 것을 뜻한다.&lt;/p&gt;
&lt;h2&gt;Protobuf에서 필드 이름보다 번호가 중요한 이유는 무엇인가&lt;/h2&gt;
&lt;p&gt;와이어 포맷이 이름이 아니라 번호로 필드를 인코딩하기 때문이다. 각 언어의 생성된 코드는 이
번호를 읽고 쓴다. &lt;code&gt;.proto&lt;/code&gt; 파일의 &lt;code&gt;email&lt;/code&gt;이라는 필드 이름은 사람을 위한 편의일 뿐,
네트워크로 전송되는 바이너리 바이트에는 전혀 닿지 않는다. 필드 이름을 바꾸는 것, &lt;code&gt;email&lt;/code&gt;을
&lt;code&gt;email_address&lt;/code&gt;로 바꾸는 것은 번호가 그대로인 한 바이너리 와이어에서 안전하며, 이것은 리네임된
JSON 키가 정확히 클라이언트를 망가뜨리는 종류의 변경인 REST에 익숙한 엔지니어를 놀라게 한다.
예외도 바로 그 REST와 같은 경우다. &lt;a href=&quot;https://protobuf.dev/programming-guides/json/&quot;&gt;ProtoJSON과 텍스트 형식&lt;/a&gt;은
이름을 직렬화하므로, 이름 변경은 JSON 트랜스코딩(예: grpc-gateway), 텍스트 형식 파일, 필드 마스크를
망가뜨린다. 같은 필드의 번호를 다시 매기는 것, 이름은 유지하되 &lt;code&gt;1&lt;/code&gt;을 &lt;code&gt;7&lt;/code&gt;로 바꾸는 것은 정반대다. 이름만
보여주는 코드 리뷰에서는 보이지 않으면서, 그 순간부터 클라이언트가 보내거나 받는 모든 메시지를
망가뜨린다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;변경&lt;/th&gt;
&lt;th&gt;와이어에서 안전한가&lt;/th&gt;
&lt;th&gt;이유&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;필드 이름 변경, 번호 유지&lt;/td&gt;
&lt;td&gt;바이너리는 예, JSON과 텍스트는 아니오&lt;/td&gt;
&lt;td&gt;바이너리 인코딩은 번호를 사용한다. ProtoJSON과 텍스트 형식은 이름을 사용한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;필드 번호 변경&lt;/td&gt;
&lt;td&gt;아니오&lt;/td&gt;
&lt;td&gt;모든 기존 메시지가 이제 다른 필드로 읽힌다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;새 번호로 새 필드 추가&lt;/td&gt;
&lt;td&gt;예&lt;/td&gt;
&lt;td&gt;오래된 클라이언트는 모르는 필드를 무시한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;필드를 삭제하고 그 옛 번호를 다른 용도로 재사용&lt;/td&gt;
&lt;td&gt;아니오&lt;/td&gt;
&lt;td&gt;오래된 데이터가 잘못된 새 필드로 디코딩된다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;필드 타입을 비호환적으로 변경 (예: &lt;code&gt;int32&lt;/code&gt;를 &lt;code&gt;string&lt;/code&gt;으로)&lt;/td&gt;
&lt;td&gt;아니오&lt;/td&gt;
&lt;td&gt;와이어 인코딩은 타입마다 다르다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;필드 삭제가 REST JSON 응답에서의 같은 일과 다른 이유는 무엇인가&lt;/h2&gt;
&lt;p&gt;번호가 방사성을 띠게 되기 때문이다. &lt;a href=&quot;https://protobuf.dev/programming-guides/proto3/&quot;&gt;Protobuf 자체 가이드&lt;/a&gt;는 삭제된 필드의 번호를
&lt;code&gt;reserved&lt;/code&gt;로 표시하고 재사용을 허용하지 말 것을 권장하는데, 실제 피해가 발생하는 곳이 바로
그 재사용이기 때문이다. 몇 달 전 생성된 코드로 여전히 실행되는 클라이언트가 오래된 필드
번호를 오래된 값을 위해 보내면, 그 번호가 이제 다른 것을 의미한다고 기대하는 서버는 데이터를
바로 거부하는 대신 조용히 잘못 해석한다. REST에는 이에 상응하는 함정이 없다. 삭제된 JSON
키는 그냥 더 이상 도착하지 않을 뿐이고, 오래된 클라이언트의 요청이 조용히 다른 것으로
재해석되는 방법은 존재하지 않는다. 메시지 앞에 &lt;code&gt;reserved 4, 9, 12;&lt;/code&gt;를 가진 &lt;code&gt;.proto&lt;/code&gt; 파일은
영구적인 흉터이며, 그것이 핵심이다. 그 번호가 자신의 이력을 모르는 누군가에 의해 새 필드에
넘어가는 것을 막는다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-protobuf&quot;&gt;message Invoice {
  reserved 4; // 예전에는 `legacy_customer_id`, 2026-06-01에 삭제
  reserved &amp;quot;legacy_customer_id&amp;quot;; // JSON/텍스트용으로 이름도 예약
  string customer_id = 5;
  string status = 6;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;필드 추가는 애초에 체인지로그 항목을 필요로 하는가&lt;/h2&gt;
&lt;p&gt;보통 breaking change 항목은 아니지만 흔히 일반 항목은 필요하다. &amp;quot;와이어에서 안전함&amp;quot;과
&amp;quot;신경 쓰는 독자에게 보임&amp;quot;은 서로 다른 주장이기 때문이다. 응답 메시지에 필드를 추가하는 것은
구조적으로 공짜이며, 오래된 클라이언트는 메시지를 디코딩하고 새 필드를 자동으로 무시한다.
하지만 이 서비스에 대해 새 통합을 구축하는 사람은 누군가 말해주지 않는 한 그 필드가
존재한다는 것을 알 방법이 없다. 성공한 빌드나 통과한 테스트 중 어느 것도 새로운 옵션 필드를
보이게 만들지 않기 때문이다. &lt;a href=&quot;https://changeloop.dev/blog/ko/api-changelog/&quot;&gt;체인지로그 API&lt;/a&gt;는 추가적 항목이
독자에게 빚지고 있는 것을 일반적으로 다룬다. 그럼에도 gRPC에 특유한 이유로 그것을 써야 하는
것은, 디버거에서 REST 응답을 훑어보다가 새 키가 나타난 것을 알아차리는 것에 상응하는 것이
존재하지 않기 때문이다.&lt;/p&gt;
&lt;h2&gt;GraphQL 호출자가 마주하는 것과는 어떻게 다른가&lt;/h2&gt;
&lt;p&gt;추가에 관한 규칙은 같지만, 노출되는 방식이 다르다. &lt;a href=&quot;https://changeloop.dev/blog/ko/graphql-schema-deprecation/&quot;&gt;GraphQL 스키마 폐기&lt;/a&gt;는
클라이언트가 명시적으로 요청한 필드만 받는 모델을 다루는데, 이는 추가적 변경을 본질적으로
무위험으로 만들고 삭제만을 진짜 위험으로 만든다. 반면 gRPC 클라이언트는 서버가 보내는 모든
것을 받고, 자신의 컴파일된 스키마 사본에 대해 전부 디코딩한다. 클라이언트의 노출은 요청한
것이 아니라 그 생성된 코드가 읽을 수 있는 것만으로 제한된다. 이 차이는 체인지로그를 쓰는
데 중요하다. GraphQL 항목은 클라이언트가 요청하지 않은 필드로부터 보호받는다고 합리적으로
가정할 수 있지만, gRPC 항목은 그것을 전혀 가정할 수 없다.&lt;/p&gt;
&lt;h2&gt;gRPC 서비스의 버전 관리는 REST의 &lt;code&gt;/v1/&lt;/code&gt;, &lt;code&gt;/v2/&lt;/code&gt;와 같은 방식으로 작동하는가&lt;/h2&gt;
&lt;p&gt;의도는 같아도 메커니즘은 다르다. &lt;a href=&quot;https://changeloop.dev/blog/ko/api-versioning-best-practices/&quot;&gt;REST API에서 v1과 v2란 무엇인가&lt;/a&gt;는
버전 관리를 서로 다른 계약을 제공하는 병렬 URL 경로로 다룬다. gRPC 서비스는 보통 &lt;code&gt;.proto&lt;/code&gt;
파일 자체 안의 패키지 이름을 통해 버전이 관리되며, &lt;code&gt;payments.v1.InvoiceService&lt;/code&gt;가
&lt;code&gt;payments.v2.InvoiceService&lt;/code&gt;가 된다. 이것은 클라이언트가 요청하는 URL 세그먼트가 아니라
클라이언트가 다이얼하는 완전한 자격을 갖춘 서비스 이름을 바꾼다. 두 접근 방식 모두 같은
문제를 해결한다. 새 계약이 존재하는 동안 오래된 계약이 계속 작동하게 하는 것이다. 하지만
REST 배경을 가진 팀은 흔히 잘못된 곳에서 버전 번호를 찾다가 그 작업을 패키지 선언이 하고
있다는 것을 놓친다.&lt;/p&gt;
&lt;h2&gt;gRPC 체인지로그 항목은 실제로 무엇을 지칭해야 하는가&lt;/h2&gt;
&lt;p&gt;메시지, 필드 번호, 그리고 그 변경이 추가적인지 아니면 마이그레이션이 필요한 삭제인지, 이
순서가 행동할지 결정하는 독자에게 중요한 순서다. &amp;quot;&lt;code&gt;Order&lt;/code&gt;에 &lt;code&gt;shipping_address&lt;/code&gt;(필드 8)
추가&amp;quot;는 통합자에게 생성된 코드를 업데이트하고 사용을 시작하는 데 필요한 모든 것을 알려준다.
&amp;quot;&lt;code&gt;Invoice&lt;/code&gt;의 필드 4 예약, &lt;code&gt;legacy_customer_id&lt;/code&gt; 사라짐&amp;quot;은 자신의 코드베이스 안의 무언가가
여전히 그 필드를 읽고 있지 않은지 확인하라고 알려주는데, 이것은 REST 스타일의 &amp;quot;응답에서
필드 삭제됨&amp;quot;이라는 메모가 같은 긴급함으로 전달하지 못하는 것이다. REST 삭제는 단지 더
적은 데이터를 반환할 뿐이지만, Protobuf 필드 재사용은 그것을 적극적으로 망가뜨리기
때문이다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;필드 타입이 와이어 포맷을 망가뜨리지 않고 변경될 수 있는 경우가 있는가?&lt;/strong&gt;
Protobuf가 문서화하는 특정 호환 그룹 내에서만, 예를 들어 어떤 경우에는 &lt;code&gt;int32&lt;/code&gt;를 &lt;code&gt;int64&lt;/code&gt;로
확장하는 것이다. Protobuf 자체의 호환성 표에 비추어 확인하지 않는 한 어떤 타입 변경도
breaking으로 취급하라. 언어의 타입 시스템과의 유추로 호환성을 가정하는 것이 잘못되는
방식이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Protobuf의 필드 폐기는 GraphQL의 &lt;code&gt;@deprecated&lt;/code&gt; 지시어처럼 작동하는가?&lt;/strong&gt;
비슷하다. Protobuf는 도구가 표시할 수 있는 필드 옵션 &lt;code&gt;[deprecated = true]&lt;/code&gt;를 지원한다.
어느 쪽도 강제되지 않는다. GraphQL 서버는 폐기된 필드에 대한 쿼리에도 여전히 응답하고,
protobuf 클라이언트도 여전히 그것을 인코딩한다. 둘 다 권고적이며 같은 체인지로그 지원을 필요로 한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;모든 클라이언트를 통제한다면 번호를 다시 매기는 것이 안전한가?&lt;/strong&gt;
완전히 폐쇄된 시스템에서는 원칙적으로 그렇지만, 그것은 필드 번호가 존재하는 이유인
안전성이라는 속성 전체를 제거한다. &amp;quot;우리는 모든 클라이언트를 통제한다&amp;quot;는 빌드가
캐시되거나, 배포가 지연되거나, 아무도 기억하지 못한 클라이언트가 추가되는 순간 더 이상
참이 아니게 되는 주장이다. 사내에서도 번호를 재사용하는 대신 예약하라.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;gRPC 서비스는 공개 REST API처럼 체인지로그 페이지가 필요한가?&lt;/strong&gt;
&lt;code&gt;.proto&lt;/code&gt; diff를 직접 읽지 않는 외부 팀이 그것을 소비할 때만, 이것은 &lt;a href=&quot;https://changeloop.dev/blog/ko/internal-api-changelog/&quot;&gt;내부 API
체인지로그&lt;/a&gt;가 일반적으로 적용하는 &amp;quot;반대편에 누가
있는가&amp;quot;라는 테스트와 같다. 같은 팀의 다른 서비스만 소비하는 gRPC 서비스는 공식
체인지로그 없이 커밋 히스토리에 의존하는 것으로 충분한 경우가 많다. 그것을 읽는 사람은
누구나 이미 스키마를 열어두고 있기 때문이다.&lt;/p&gt;
</content:encoded></item><item><title>체인지로그 파일 형식, JSON인가 YAML인가 그냥 Markdown인가</title><link>https://changeloop.dev/blog/ko/changelog-file-formats/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/changelog-file-formats/</guid><description>체인지로그 파일의 형식은 페이지와 위젯을 공급할 수 있는지 사람만 읽는지를 정한다. Markdown, JSON, YAML이 각각 치르는 대가를 비교한다.</description><pubDate>Thu, 17 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;대부분의 팀은 체인지로그를 Markdown 파일로 시작한다, 그것이 저항이 가장 적은 길이기 때문이다: pull request의 diff에서 읽을 수 있고, 아무것도 렌더링하지 않고 GitHub에서 읽을 수 있으며, README를 써본 적 있는 누구에게나 친숙하다. 그 선택은 사람이 아닌 무언가, 페이지, 위젯, 이메일 다이제스트가 파일을 읽어야 할 때까지는 잘 작동하고, 그때 형식은 공짜이기를 멈춘다. &lt;a href=&quot;https://changeloop.dev/blog/ko/changelog-automation/&quot;&gt;체인지로그 자동화&lt;/a&gt;는 구조적 요구사항을 일반적으로 다룬다, 타입, 날짜, 본문, 링크. 이것은 어떤 파일 형식이 실제로 그 구조를 전달하는지, 그리고 각각 그곳에 도달하는 데 무엇이 드는지에 관한 것이다.&lt;/p&gt;
&lt;h2&gt;단순한 Markdown 체인지로그의 문제는 무엇인가&lt;/h2&gt;
&lt;p&gt;없다, 무언가 그것을 다시 필드로 파싱해야 할 때까지는. 제목, 날짜, 그 아래 글머리 목록은 사람이 읽기에는 사소하지만 신뢰성 있게 파싱하기는 진짜 어렵다, Markdown에는 스키마가 없기 때문이다: 날짜는 제목에 있을 수도, 첫 줄에 굵게 있을 수도, 오래된 항목에서는 아예 빠져 있을 수도 있으며, 그 변형들 각각은 사람은 정확히 읽고 파서는 그렇지 못하는 유효한 Markdown이다. Markdown 체인지로그를 자동화하는 팀은 대개 항목의 포맷이 조금이라도 벗어나는 순간 깨지는, 정규식 기반의 자체 제작 파서를 쓰는 것으로 끝난다, 이는 흔히 일어난다, 쓸 때 일관성을 강제하는 것이 아무것도 없기 때문이다.&lt;/p&gt;
&lt;h2&gt;구조화된 형식이 실제로 주는 것은 무엇인가&lt;/h2&gt;
&lt;p&gt;모든 항목이 같은 형태를 가진다는 보장이며, 읽힐 때 추측되는 대신 쓰일 때 검증된다. 정의된 스키마를 가진 JSON이나 YAML 파일, 타입, 날짜, 버전, 대상, 본문, 링크는, 엄격한 API 응답이 그러하듯이 필수 필드가 빠지면 시끄럽게 실패한다. Markdown 파일은 그저 거기 있는 것을 렌더링할 뿐이다, 맞든 틀리든. 그 차이는 스크립트가 피드를 정렬하기 위해 각 항목의 날짜를 필요로 하고 항목의 절반이 그것을 다른 곳에 가지고 있는 날까지 보이지 않는다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# CHANGELOG.yml
- date: 2026-09-05
  type: breaking
  version: v2
  audience: api
  body: &amp;quot;POST /invoices now rejects a currency mismatch instead of silently converting.&amp;quot;
  link: /blog/api-changelog/
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;그것은 사람이 읽을 수 있는 파일이 사라져야 한다는 뜻인가&lt;/h2&gt;
&lt;p&gt;아니다, 그리고 YAML이나 JSON 파일이 사람이 pull request에서 읽는 것 역할까지 겸하게 만들려는 시도는 대개 반대 방향의 실수다: 중첩된 JSON의 diff를 검토하는 것은 산문 한 문장을 검토하는 것보다 나쁘며, 표현 오류를 잡기 위해 데이터 구조를 머릿속으로 파싱해야 하는 검토자는 결국 표현 오류 잡기를 멈추는 검토자다. 두 형식은 공존할 수 있다: 구조화된 데이터는 자동화 파이프라인이 읽는 진실의 원천이고, 생성된 Markdown이나 HTML 렌더링은 사람이 실제로 검토하고 읽는 것이며, 손으로 옆에 유지되는 대신 구조화된 파일로부터 만들어진다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;형식&lt;/th&gt;
&lt;th&gt;있는 그대로 사람이 읽을 수 있는가&lt;/th&gt;
&lt;th&gt;커스텀 코드 없이 기계가 파싱할 수 있는가&lt;/th&gt;
&lt;th&gt;흔한 실패 모드&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Markdown&lt;/td&gt;
&lt;td&gt;예&lt;/td&gt;
&lt;td&gt;아니오&lt;/td&gt;
&lt;td&gt;일관되지 않은 항목 형태가 단순한 파서를 깬다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JSON&lt;/td&gt;
&lt;td&gt;나쁨&lt;/td&gt;
&lt;td&gt;예&lt;/td&gt;
&lt;td&gt;장황함; 손으로 편집하면 유효하지 않은 JSON이 되기 쉬움&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;YAML&lt;/td&gt;
&lt;td&gt;그럭저럭&lt;/td&gt;
&lt;td&gt;예&lt;/td&gt;
&lt;td&gt;공백에 민감함; 잘못된 들여쓰기는 시끄럽지 않고 조용한 파싱 오류다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;어느 구조화된 형식이 실제로 손으로 편집하기 더 쉬운가, JSON인가 YAML인가&lt;/h2&gt;
&lt;p&gt;YAML이다, 생성기 대신 손으로 항목을 쓰는 누구에게나. JSON이 모든 문자열과 중첩된 객체에 요구하는 따옴표 붙이기와 괄호 맞추기를 없애기 때문이다. 트레이드오프는 YAML의 공백 민감성이 JSON의 괄호 불일치가 보통 그러지 않는 방식으로 조용히 실패한다는 것이다: JSON 파서는 잘못된 형식의 입력을 곧바로 거부하는 반면, YAML 파서는 잘못 들여쓰인 파일을 받아들여 그냥 잘못된 구조로 파싱해버릴 수 있으며, 이는 그것이 일어났다는 것을 아무것도 알려주지 않기 때문에 더 나쁜 실패다. 항목이 항상 스크립트에 의해서만 쓰인다면, 이 트레이드오프는 대체로 사라지고 JSON의 더 엄격한 파싱이 더 안전한 기본 선택이 된다.&lt;/p&gt;
&lt;h2&gt;체인지로그 페이지는 그것을 공급하는 파일과 별개의 자체 구조화된 형식이 필요한가&lt;/h2&gt;
&lt;p&gt;별개의 것이 아니라, 다르게 렌더링된 같은 것이. &lt;a href=&quot;https://changeloop.dev/blog/ko/changelog-page/&quot;&gt;체인지로그 페이지&lt;/a&gt;는 JSON 피드와 schema.org 마크업을 통해 페이지 자체를 기계가 읽을 수 있게 만드는 법을 다룬다. 그 피드는 생성된 출력이지, 근본적인 파일과 동기화된 상태로 유지해야 할 두 번째 진실의 원천이 아니다. 소스 파일과 페이지의 피드라는 두 곳에서 구조화된 데이터를 손으로 유지하는 것이 그 둘이 결국 갈라지는 방식이며, 그래서 여기서 내려지는 파일 형식 결정은 이후의 모든 것, 페이지, 위젯, 이메일이 생성되는 유일한 것이어야 하고, 절대 손으로 복사되어서는 안 된다.&lt;/p&gt;
&lt;h2&gt;기존 Markdown 체인지로그를 구조화된 형식으로 변환하는 마이그레이션 비용은 가치가 있는가&lt;/h2&gt;
&lt;p&gt;보통 자동화가 실제 목표가 되었을 때만 그렇지, 그 전에는 아니다. GitHub README에 Markdown 파일을 발행하는 1인 프로젝트는 실질적인 자동화 필요가 없으며, 그것을 YAML로 변환하는 것은 의식 절차 외에는 아무것도 사지 못한다. 그 변환은 페이지, 요약 이메일, 공개 피드 같은 하나 이상의 다운스트림 소비자가 같은 데이터를 읽어야 할 때 스스로 값을 한다, 그것이 정확히 Markdown 파서의 비일관성이 유지하기 짜증나는 것을 넘어 눈에 띄게 잘못된 출력을 만들어내기 시작하는 지점이기 때문이다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Markdown 체인지로그를 형식을 완전히 바꾸지 않고 파싱 가능하게 만들 수 있는가?&lt;/strong&gt;
부분적으로, frontmatter로: 산문을 위한 Markdown 본문 옆에 각 항목 맨 위의 작은 YAML 블록(날짜, 타입, 버전). 이것은 전체 항목을 JSON이나 YAML로 강제하지 않고도 파서가 필요로 하는 구조화된 필드를 얻으며, 완전한 마이그레이션에 아직 준비되지 않은 팀에게 합리적인 중간 지점이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;파일 형식이 SEO나 체인지로그 페이지의 순위에 영향을 주는가?&lt;/strong&gt;
직접적으로는 아니다. 검색 엔진은 렌더링된 페이지를 읽지 소스 파일을 읽지 않으므로 파일 형식은 그들에게 보이지 않는다. 페이지 자체에 중요한 것은 그것이 자체적으로 기계가 읽을 수 있는지 여부이며, 이는 무엇이 그것을 생성하는지와는 별개의 문제다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;모든 체인지로그 항목이 같은 파일을 거쳐야 하는가, 아니면 타입별로 여러 파일에 나눌 수 있는가?&lt;/strong&gt;
하나의 파일이 항목 양이 diff나 검토를 불편하게 만들기 전까지는 더 단순하다. 연도나 카테고리별 분할은 하나의 파일의 diff가 합리적으로 검토하기에 너무 커질 때 합리적인 안전 밸브이지만, 다운스트림의 무언가가 &amp;quot;모든 항목&amp;quot;을 하나의 목록으로 읽을 수 있기 전에 병합 단계를 추가한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;RSS에 표준이 있듯이 표준 체인지로그 파일 형식이 존재하는가?&lt;/strong&gt;
널리 채택된 것은 없다. Keep a Changelog는 Markdown 관례를 제안하고, 여러 도구가 자체 형식을 가지고 있다. &lt;a href=&quot;https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md&quot;&gt;changeset&lt;/a&gt;은 패키지와 버전 올림 수준을 지정하는 YAML frontmatter가 붙은 Markdown 파일로, 앞에서 설명한 frontmatter 패턴 그대로다. 이들 중 어느 것도 RSS 리더가 보편적으로 RSS를 이해하듯이 다른 도구들이 바로 읽는 형식은 아니다.&lt;/p&gt;
</content:encoded></item><item><title>중복된 기능 요청, 목소리를 잃지 않고 병합하기</title><link>https://changeloop.dev/blog/ko/duplicate-feature-requests/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/duplicate-feature-requests/</guid><description>중복된 기능 요청을 묶으면 개수는 지키지만, 부주의하게 병합하면 유용했던 표현이 사라진다. 표현을 지키는 병합과 잘못된 일치를 가려내는 법을 다룬다.</description><pubDate>Thu, 17 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;세 명의 고객이 서로 다른 세 주에, 서로 다른 세 가지 표현으로 같은 기능을 요청한다. 중복을 잡기 위해 만들어진 분류 프로세스는 제 일을 한다: 그것들을 묶고, 세 표를 가진 하나의 요청으로 세고, 백로그는 깨끗하게 유지된다. 그것이 쉬운 부분이다. &lt;a href=&quot;https://changeloop.dev/blog/ko/feature-request-tracking/&quot;&gt;어떤 라벨이 가치 있는가&lt;/a&gt;는 표현으로 분류하기 전에 근본 기능으로 묶는 것을 중복에 대한 기계적 해결책으로 다룬다. 다루지 않는 것은 세 요청이 한 줄이 되는 순간 말 자체에 무슨 일이 일어나는가이며, 그 손실은 보통 그것이 해결한 중복 계산 문제보다 크다.&lt;/p&gt;
&lt;h2&gt;중복이 병합될 때 실제로 무엇이 사라지는가&lt;/h2&gt;
&lt;p&gt;각 요청자가 사용한 구체적인 표현으로, 그것이 무너져 들어가는 표 수보다 정보가 많은 경우가 많다. 한 고객은 &amp;quot;필터링된 결과를 내보낼 방법&amp;quot;을 요청할 수 있고, 다른 고객은 &amp;quot;저장된 필터를 존중하는 CSV 내보내기&amp;quot;를, 세 번째 고객은 &amp;quot;숨겨진 열을 포함하지 않는 내보내기&amp;quot;를 요청할 수 있다. 셋 다 같은 근본 요청이고 올바르게 묶였지만, 각 표현은 그 사람에게 무엇이 중요한지에 대해 약간 다른 강조를 담고 있으며, 첫 제출의 표현만 유지하는 병합은 다른 두 개를 완전히 버린다. 개수는 살아남는다; 누군가 기능의 올바른 버전을 만드는 데 도움이 될 질감은 그렇지 않다.&lt;/p&gt;
&lt;h2&gt;표 수가 이미 수요가 존재한다고 말하는데 왜 질감이 중요한가&lt;/h2&gt;
&lt;p&gt;수요와 설계는 다른 질문이고, 오직 구체적인 표현만이 두 번째 질문에 답하기 때문이다. &amp;quot;내보내기&amp;quot;에 대한 열 표는 팀에게 그 기능을 만들 가치가 있다고 말한다; &amp;quot;내보내기&amp;quot;가 CSV를 의미하는지, PDF를 의미하는지, 예약된 이메일을 의미하는지, API 엔드포인트를 의미하는지에 대해서는 아무것도 말하지 않는다. 첫 제출의 표현을 위해 열 개 중 아홉 개의 원래 제출을 버리는 병합은, 나머지 아홉이 미묘하게 다른 것을 원했더라도 첫 요청자가 우연히 요청한 것으로 사양을 조용히 좁힐 수 있다. &lt;a href=&quot;https://changeloop.dev/blog/ko/feature-request-tracking/&quot;&gt;기능 요청이 실제로 무엇을 기록해야 하는가&lt;/a&gt;는 정확히 이 격차를 접수 쪽에서 다룬다; 중복 병합은 그것이 접수 후에 다시 나타나는 지점이며, 팀이 실제로 요청된 것의 범위를 가장 필요로 하는 바로 그 지점이다.&lt;/p&gt;
&lt;h2&gt;표현을 버리는 대신 지키는 병합 과정은 어떤 모습인가&lt;/h2&gt;
&lt;p&gt;교체 대신 추가. 정본 항목은 백로그 뷰를 위해 하나의 제목을 유지하지만, 병합된 각 제출의 원래 표현은 인용 목록으로든 연결된 소스 티켓으로든 거기에 계속 붙어 있어서, 나중에 항목을 검토하는 누구든 팀원 한 명의 요약 대신 사람들이 실제로 요청한 것의 진짜 범위를 볼 수 있다. 이것은 만드는 데 거의 아무 비용도 들지 않는다, 새 시스템 대신 티켓의 필드 하나이며, 정보를 압축하는 병합과 그저 그것의 표시만 압축하는 병합의 차이다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;기능: 필터링된 CSV 내보내기
표: 12
병합된 요청:
  - &amp;quot;필터링된 결과를 내보낼 방법&amp;quot; (acct_4421)
  - &amp;quot;저장된 필터를 존중하는 CSV 내보내기&amp;quot; (acct_8832)
  - &amp;quot;숨겨진 열을 포함하지 않는 내보내기&amp;quot; (acct_1097)
  ...
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;모든 중복이 병합될 가치가 있는가, 아니면 잘못된 일치가 있는가&lt;/h2&gt;
&lt;p&gt;일부는 잘못된 일치이며, &amp;quot;비슷하게 들린다&amp;quot;를 &amp;quot;같은 요청이다&amp;quot;로 취급하는 것은 그 자체로 하나의 실패 모드다. &amp;quot;내 데이터를 내보내게 해달라&amp;quot;와 &amp;quot;필터링된 뷰만 내보내게 해달라&amp;quot;는 실제로는 같은 일반적 기능의 두 다른 범위를 설명하면서도 &amp;quot;내보내기&amp;quot;에 대한 키워드 일치로 묶일 수 있다; 그것들을 병합하면 잘못된 것에 대한 표 수를 부풀리거나, 더 나쁘게는, 우연히 먼저 도착했다는 이유로 더 좁은 버전을 내놓게 된다. 묶음에 대한 사람의 검토는, 빠른 검토라도, 그것이 쌓이기 전에 이것을 잡아낸다; 자동 유사성 일치만으로는 어휘 기준으로 과도하게 병합하고 의도 기준으로 부족하게 병합할 것이다.&lt;/p&gt;
&lt;h2&gt;중복 확인은 실제로 언제 실행해야 하는가, 접수 시점인가 나중인가&lt;/h2&gt;
&lt;p&gt;둘 다, 이유는 다르다. 접수 시점에 확인하면 뻔한 경우, 즉 이미 열려 있는 것을 그대로 되풀이하는 새 요청이 그 자체로 추적되지 않는 독립 항목이 되기 전에 잡아낸다. 제출 시점에 열린 요청들에 대해 유사성 검색을 돌리면 사람 없이도 이런 경우 대부분을 처리한다. 나중에 더 느린 주기로 돌리는 두 번째 확인은 접수 단계가 놓치는 경우를 잡아낸다. 당시에는 키워드나 임베딩 일치를 피해 갈 만큼 표현이 달랐던 두 요청이, 팀이 십여 개의 변형을 본 뒤에야 사실은 같은 기저 기능을 설명하고 있었다는 것이 드러나는 경우다. 두 번째 확인을 건너뛰면 거의 중복인 항목들이 서로 다른 제목 아래 무기한 흩어진 채로 남고, 각각의 표 수는 그것을 만들게 했을 숫자로 결코 합쳐지지 않는다.&lt;/p&gt;
&lt;h2&gt;요청자는 자신의 제출이 기존 항목에 병합되었다는 것을 알아야 하는가&lt;/h2&gt;
&lt;p&gt;그렇다, 그리고 이것은 &lt;a href=&quot;https://changeloop.dev/blog/ko/customer-feedback-loop/&quot;&gt;고객 피드백 루프 닫기&lt;/a&gt;와 같은 규율을, 평소보다 한 단계 일찍 적용한 것이다: 무언가를 제출하고 두 번 다시 아무것도 듣지 못하는 요청자는, 그것이 결국 출시된 다른 열한 표를 가진 항목에 올바르게 병합되었더라도, 자신의 요청이 아무 데도 가지 못했다고 결론짓는다. &amp;quot;이것을 다른 사람들도 한 기존 요청과 결합했습니다&amp;quot;라는 짧은 확인은 메시지 하나의 비용이 들며, 고객이 그것이 실제로 추적된 적이 있는지 알 수 없어서 몇 달마다 같은 요청을 다시 제출하는 것을 막는다.&lt;/p&gt;
&lt;h2&gt;병합은 기능이 출시될 때 누구에게 공이 돌아가는지를 바꾸는가&lt;/h2&gt;
&lt;p&gt;먼저 제출한 사람뿐 아니라 모두를 포함해야 한다. &lt;a href=&quot;https://changeloop.dev/blog/ko/customer-feedback-loop/&quot;&gt;피드백 루프 닫기&lt;/a&gt;는 요청이 출시될 때 요청자에게 알리는 것을 다룬다; 병합된 항목의 경우 그것은 정본 제목이 된 표현을 가진 계정뿐 아니라 병합에 붙은 모든 계정을 의미한다, 각 요청자의 관점에서는 그녀가 이것을 요청했고 그것이 출시되었기 때문이며, 분류 프로세스가 우연히 어느 표현을 유지했는지와는 무관하다. Changeloop에서는 pull request가 연결된 모든 이슈를 지정한다는 뜻이다(&lt;code&gt;Fixes #142, fixes #187&lt;/code&gt;). 지정되지 않은 이슈에는 코멘트가 달리지 않는다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;병합된 요청당 얼마나 많은 표현을 지킬 가치가 있는가, 인용인가 완전한 티켓 링크인가?&lt;/strong&gt;
짧은 인용이 보통 흔한 경우에는 충분하다, 그 목적이 검토자가 표현의 범위를 한눈에 볼 수 있게 하는 것이기 때문이다; 원본에 스크린샷이나 한 줄 인용이 평평하게 만들어버릴 상세한 워크플로 설명 같은 상당한 추가 맥락이 있었다면 완전한 티켓 링크도 지켜라.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;각 중복의 표현을 지키는 것이 백로그를 스캔하기 더 어렵게 만드는가?&lt;/strong&gt;
기본적으로 접혀 있다면 아니다. 정본 제목은 빠르게 훑어보는 검토자가 보는 것이다; 병합된 표현은 클릭 한 번이나 펼침 한 번 떨어져 있어서, 더 깊은 조사를 하는 사람에게는 존재하지만 그저 표를 세는 사람의 뷰를 어지럽히지는 않는다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;두 요청이 동일해 보이지만 만들고 보니 다른 것을 원했던 것으로 밝혀지면 어떻게 하는가?&lt;/strong&gt;
그것이 명확해지는 순간 다시 분리하고, 원래 병합을 반복을 피해야 할 실수로서가 아니라 당시 가용했던 정보로 내려진 합리적인 결정으로 취급하라. 아무것도 다시 나누지 않는 묶음 시스템은 결국 몇 개의 잘못된 병합을 영구히 굳혀버리게 될 것이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;병합된 요청이 근본 표현에 대한 사람의 검토를 받아야 하는 표 임계값이 있는가?&lt;/strong&gt;
고정된 숫자는 없지만, 제작 결정에 다가가는 어떤 요청이든 표 수와 무관하게 그것을 받을 자격이 있다, 그것이 &amp;quot;내보내기&amp;quot;와 &amp;quot;저장된 필터가 있는 CSV로서의 내보내기&amp;quot; 사이의 차이가 뉘앙스이기를 멈추고 사양이 되기 시작하는 지점이기 때문이다.&lt;/p&gt;
</content:encoded></item><item><title>버전 번호 없는 GraphQL 비추천 처리</title><link>https://changeloop.dev/blog/ko/graphql-schema-deprecation/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/graphql-schema-deprecation/</guid><description>GraphQL은 URL에 v1이나 v2가 없고 필드를 지시어로 하나씩 비추천 처리한다. 이는 체인지로그가 지는 책임을 바꾼다. 파괴적 변경과 안전한 제거법을 다룬다.</description><pubDate>Thu, 17 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;REST API는 &lt;code&gt;/v1/&lt;/code&gt; 옆에 &lt;code&gt;/v2/&lt;/code&gt;를 발행하고 호출자가 자기 속도로 이동하게 둘 수 있다. GraphQL은 하나의 엔드포인트에 하나의 스키마를 가지며, 작년 빌드의 모바일 앱과 오늘 아침 배포된 내부 대시보드를 포함한 모든 클라이언트가 같은 그래프를 조회한다. 포크할 URL이 없다. 필드를 비추천 처리한다는 것은 모두가 이미 의존하고 있는 스키마 안에서 그것을 그 자리에 비추천으로 표시한다는 뜻이며, 이는 규율을 REST와 다르게 만든다. 호출자에게 무언가가 사라질 것이라고 말하는 근본적인 문제는 &lt;a href=&quot;https://changeloop.dev/blog/ko/api-deprecation/&quot;&gt;API 비추천 처리&lt;/a&gt;가 일반적으로 다루는 것과 같은데도 그렇다.&lt;/p&gt;
&lt;h2&gt;올릴 버전이 없다면 GraphQL은 필드를 비추천으로 어떻게 표시하는가&lt;/h2&gt;
&lt;p&gt;필드에 직접 적용되는 &lt;a href=&quot;https://spec.graphql.org/October2021/#sec--deprecated&quot;&gt;&lt;code&gt;@deprecated&lt;/code&gt; 지시어&lt;/a&gt;로:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;type Product {
  price: Float @deprecated(reason: &amp;quot;Use priceV2 for multi-currency support.&amp;quot;)
  priceV2: Money
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;필드는 계속 조회 가능하다. 사라지지 않고, 404를 반환하지 않고, 동작을 바꾸지 않는다. 그저 GraphiQL, Apollo Studio, 스키마 린터 같은 대부분의 GraphQL 도구가 스키마를 둘러보거나 그것에 대해 쿼리를 작성하는 누구에게나 보여줄 기계가 읽을 수 있는 메모를 담고 있을 뿐이다. 이것이 메커니즘의 전부다. 별도의 비추천 처리 엔드포인트도, 헤더도, 스펙이 요구하는 동반 문서도 없으며, 이는 매력이자 함정이다. 지시어는 추가하기 쉽고 무시하기도 쉽다. 클라이언트가 그것을 보도록 강제하는 것이 아무것도 없기 때문이다.&lt;/p&gt;
&lt;h2&gt;누군가 비추천 처리 이유를 실제로 보기는 하는가&lt;/h2&gt;
&lt;p&gt;스키마를 직접 사용하는 사람, 즉 인트로스펙션이나 스키마를 인식하는 편집기를 통해 사용하는 사람만 본다. 그리고 이는 API 체인지로그의 일반적인 독자보다 작은 청중이다. 여섯 달 전 쿼리에 맞춰 만들어진 모바일 앱은 이미 그 쿼리를 바이너리에 구워 넣었다. 누군가 새 필드로 앱을 다시 만들고 업데이트를 내놓을 때까지, 비추천이든 아니든 계속 &lt;code&gt;price&lt;/code&gt;를 요청하고 계속 응답을 받을 것이다. 지시어는 새 코드를 작성하는 개발자에게 예전 필드를 쓰지 말라고 말한다. 이미 배포되어 실행 중인 클라이언트에게는 아무것도 하지 않는다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;메커니즘&lt;/th&gt;
&lt;th&gt;누구에게 닿는가&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@deprecated&lt;/code&gt; 지시어&lt;/td&gt;
&lt;td&gt;스키마를 둘러보거나 새 쿼리를 작성하는 개발자&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;스키마 린터의 CI 실패&lt;/td&gt;
&lt;td&gt;하나를 돌린다면 클라이언트 코드베이스를 소유한 팀&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;체인지로그 항목&lt;/td&gt;
&lt;td&gt;린터 없는 클라이언트 팀을 포함해 그것을 읽는 누구든&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;아무것도 없음 (필드가 그냥 작동함)&lt;/td&gt;
&lt;td&gt;예전 필드를 쓰는 이미 만들어진 클라이언트&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;비추천된 필드도 체인지로그 항목을 받아야 하는가&lt;/h2&gt;
&lt;p&gt;그렇다, 그리고 그것은 지시어 혼자보다 더 많은 일을 한다. 체인지로그는 지시어가 닿을 수 없는 사람들에게 닿기 때문이다. 스키마를 둘러보지 않고 그래프를 소비하는 파트너 팀, 몇 달 전 캐시된 스키마 사본에 맞춰 만들어진 클라이언트, 산문을 읽어야만 알아차릴 누구에게든. &lt;a href=&quot;https://changeloop.dev/blog/ko/api-changelog/&quot;&gt;API 체인지로그&lt;/a&gt;는 항목이 호출자에게 일반적으로 무엇을 빚지는지를 다룬다. GraphQL 항목은 REST가 거의 명시적으로 밝힐 필요가 없는 한 가지를 빚지고 있다. REST 호출자는 그것을 버전 번호에서 추론하기 때문이다: 예전 필드가 오늘 여전히 작동하는지, 경고와 함께 여전히 작동하는지, 아니면 실제로 데이터를 반환하지 않게 되었는지. 지시어만으로는 스키마를 한 번도 열어본 적 없는 독자에게 이 중 어느 것도 답하지 못한다.&lt;/p&gt;
&lt;h2&gt;스키마에서 필드를 제거하는 것이 실제로 안전한 때는 언제인가&lt;/h2&gt;
&lt;p&gt;쿼리 로그가 더 이상 아무도 그것을 요청하지 않는다는 것을 보여줄 때뿐이며, 이는 사용 여부의 질문이지 달력의 질문이 아니다. 필드는 1년 동안 &lt;code&gt;@deprecated&lt;/code&gt;를 달고도 한 번도 재구축되지 않은 하나의 클라이언트에게 여전히 필수적일 수 있다. REST의 &lt;code&gt;Sunset&lt;/code&gt; 헤더가 종종 하듯이 고정된 일정에 따라 그것을 제거하면, 그 클라이언트를 아무 대응 가능한 경고 없이 망가뜨린다. GraphQL은 한 번도 읽은 적 없는 지시어 외에는 대응할 아무것도 주지 않기 때문이다. 제거 날짜를 정하기 전에 필드 수준의 사용량을 기록하고, 0이 아닌 쿼리 카운트는 카운트다운이 아니라 보류로 취급하라.&lt;/p&gt;
&lt;h2&gt;필드를 추가하는 것이 REST API에서와 같은 위험을 지니는가&lt;/h2&gt;
&lt;p&gt;새 필드라면 구조적으로 더 적다, GraphQL 클라이언트는 명시적으로 요청한 필드만 받기 때문이다. &lt;code&gt;price&lt;/code&gt; 옆에 &lt;code&gt;priceV2&lt;/code&gt;를 추가하는 것은 REST JSON 응답에 필드를 추가하는 것이 엄격한 역직렬화기를 망가뜨릴 수 있는 방식으로 기존 쿼리를 망가뜨릴 수 없다. 클라이언트가 새 필드를 요청하도록 강제하는 것이 아무것도 없기 때문이다. 같은 호흡에서 이름을 붙일 가치가 있는 예외는 기존 enum에 값을 추가하는 것이다. 강타입 언어가 권장하는, 모든 enum 값을 빠짐없이 분기하는 클라이언트는 어떤 쿼리가 그것을 요청했는지와 무관하게 새 값이 도착하는 순간 망가진다. 이 안전성은 클라이언트가 스스로 선택해 받는 필드와 유니언 멤버에만 적용되며, 클라이언트 코드가 손으로 열거하는 닫힌 집합에는 적용되지 않는다.&lt;/p&gt;
&lt;h2&gt;GraphQL 체인지로그 항목이 REST 항목에는 필요 없는 무엇을 필요로 하는가&lt;/h2&gt;
&lt;p&gt;필드 이름만이 아니라 쿼리의 형태다. &amp;quot;&lt;code&gt;price&lt;/code&gt; 필드는 비추천됨&amp;quot;은 호출자가 실제로 필요로 하는 부분, 즉 어떤 타입과 어떤 쿼리가 그것을 건드리는지를 빠뜨리기 때문이다. 유용한 항목은 타입, 필드, 대체 필드를 명시하고, 생성할 수 있다면 여전히 예전 형태를 요청하는 프로덕션의 실제 쿼리도 명시한다. 그 마지막 부분, 비추천 처리 공지를 실제 사용량과 연결하는 것은, REST 호출자는 URL에 대한 서버 로그에서 공짜로 얻지만 GraphQL 호출자는 얻지 못하는 것이다. 무엇을 요청하든 모든 쿼리가 같은 엔드포인트를 치기 때문이다.&lt;/p&gt;
&lt;h2&gt;필드가 아닌 다른 것도 &lt;code&gt;@deprecated&lt;/code&gt; 지시어를 달 수 있는가&lt;/h2&gt;
&lt;p&gt;enum 값도 가능하다, 필드가 아니라 그 값 자체의 정의에 같은 지시어를 쓴다:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;enum ShippingMethod {
  STANDARD
  EXPRESS
  OVERNIGHT @deprecated(reason: &amp;quot;Use EXPRESS with priority: true instead.&amp;quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;스펙은 안정 릴리스 기준으로 &lt;code&gt;@deprecated&lt;/code&gt;를 정확히 두 위치, 필드 정의와 enum 값에만 정의하며 그 외에는 없다. 인자와 입력 필드 수준의 비추천 처리는 아직 초안 단계 언어로만 존재하고, 오늘날 대부분의 서버가 구현하는 것에는 없다. 이렇게 표시된 enum 값은 여전히 서버가 반환하거나 받아들일 수 있는 합법적인 값으로 남는다. 비추천된 필드가 그렇듯 파괴적이지 않다는 같은 약속이며, 그래서 실제로 값을 제거하기 전에 미리 배포해도 안전하다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;GraphQL은 엔드포인트 전체를 위한 Sunset 헤더 같은 것을 지원하는가?&lt;/strong&gt;
아니다, 보통 엔드포인트가 하나뿐이기 때문이다. 비추천 처리 타이밍은 필드 수준에 있다, &lt;code&gt;@deprecated&lt;/code&gt; 지시어의 이유 텍스트 안에, 그리고 팀이 그 옆에 발행하는 어떤 체인지로그나 마이그레이션 가이드 안에 있다. 클라이언트가 프로그램적으로 읽을 수 있는 응답 헤더 안에는 없다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;비추천된 필드를 제거했다가 나중에 다른 타입으로 다시 추가할 수 있는가?&lt;/strong&gt;
새로운 필드 이름으로만 가능하다. 타입을 바꿔서 같은 필드 이름을 다시 도입하는 것은 정확히 비추천 처리 주기가 피하려고 존재하는 그 파괴적 변경이다. &lt;code&gt;priceV2&lt;/code&gt;가 하듯이 대체물에 고유한 이름을 주고, 이름이 재사용 가능해지기 전에 예전 것이 완전히 소멸하게 두라.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;@deprecated&lt;/code&gt; 이유 텍스트가 체인지로그 항목으로 링크해야 하는가?&lt;/strong&gt;
그렇다, 스키마 도구가 그것을 지원할 때는. 이유 필드는 평범한 문자열을 받아들이며, 그 문자열 안의 URL은 인트로스펙션 출력을 응시하는 개발자로부터 체인지로그 항목이 줄 수 있는 더 완전한 설명으로 가는 가장 짧은 경로다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;GraphQL 스키마 변경이 REST가 그렇지 않은 방식으로 뒤로 호환 가능한 적이 있는가?&lt;/strong&gt;
추가적 필드 변경은 그렇다, 위의 이유로: 클라이언트는 요청한 것만 받는다. 새 enum 값은 예외다, 닫힌 집합을 열거하는 클라이언트가 예상하지 못한 값에서 망가질 수 있기 때문이다. 제거와 타입 변경은 그것의 REST 대응물만큼 정확히 파괴적이다.&lt;/p&gt;
</content:encoded></item><item><title>API 마이그레이션 가이드는 어떻게 작성하는가</title><link>https://changeloop.dev/blog/ko/api-migration-guide/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/api-migration-guide/</guid><description>API 마이그레이션 가이드는 호환되지 않는 변경을 장애가 아니라 체크리스트로 바꾼다. 무엇이 필요한지, 언제 써야 하는지, 왜 항목 하나로는 부족한지 설명한다.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;API 마이그레이션 가이드란 호환되지 않는 변경을 장애가 아니라 체크리스트로 바꾸는 문서다. 무엇이 바뀌었는지, 그것에 대해 무엇을 해야 하는지, 그리고 언제까지인지. 체인지로그 항목은 호환되지 않는 변경을 두 문장으로 이름 붙일 수 있지만, 마이그레이션 가이드는 그 두 문장이 &amp;quot;이건 당신을 깨뜨린다&amp;quot;고 말할 때 호출자가 실제로 열어보는 것이며, 정확히 무엇을 수정해야 하는지 알아야 하는 순간이다. 가이드 없이 항목을 게시하는 것은 호출자가 그것을 막기 위해 쓰인 문서 대신 지원 티켓을 통해 호환되지 않는 변경을 알게 되는 방식이다.&lt;/p&gt;
&lt;h2&gt;API 마이그레이션 가이드란 무엇인가&lt;/h2&gt;
&lt;p&gt;호출자를 API의 예전 형태에서 새 형태로 데려가는 단계별 문서로, API를 채택할지 아직 결정 중인 사람이 아니라 수정할 코드가 있는 사람을 위해 작성된다. 이 구분은 중요하다. 마이그레이션 가이드는 기존 통합과 기존 프로덕션 트래픽을 전제로 하므로 롤백, 부분 마이그레이션, 마이그레이션이 성공했는지 아는 방법을 다뤄야 하는데, 첫 통합을 위한 가이드는 이 중 어느 것도 다룰 필요가 없다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;문서&lt;/th&gt;
&lt;th&gt;전제로 하는 것&lt;/th&gt;
&lt;th&gt;답하는 질문&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;마이그레이션 가이드&lt;/td&gt;
&lt;td&gt;기존 통합&lt;/td&gt;
&lt;td&gt;예전 형태에서 새 형태로 어떻게 옮기는가?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;체인지로그 항목&lt;/td&gt;
&lt;td&gt;아무것도, 독자가 확인한다는 것만&lt;/td&gt;
&lt;td&gt;무엇이 바뀌었고, 언제인가?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API 레퍼런스&lt;/td&gt;
&lt;td&gt;아무것도, 또는 첫 통합&lt;/td&gt;
&lt;td&gt;이 엔드포인트는 무엇을 하는가?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;비추천 공지&lt;/td&gt;
&lt;td&gt;예전 것을 쓰는 통합&lt;/td&gt;
&lt;td&gt;이것은 언제 작동을 멈추는가?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;마이그레이션 가이드는 보통 마지막 두 개 사이에 위치한다. 비추천 공지는 시계를 시작시키고, 마이그레이션 가이드는 그 시계가 다 되기 전에 호출자가 따르는 것이다.&lt;/p&gt;
&lt;h2&gt;변경이 체인지로그 항목만이 아니라 마이그레이션 가이드가 필요한 때는 언제인가&lt;/h2&gt;
&lt;p&gt;예전 동작과 새 동작 사이에 한 단계 이상이 있을 때, 또는 변경이 충분히 많은 호출 지점을 건드려서 호출자가 설명보다 실제로 작성된 예시에서 더 이익을 얻을 때다. &lt;a href=&quot;https://changeloop.dev/blog/ko/breaking-changes/&quot;&gt;호환되지 않는 변경이란 무엇이고 어떻게 출시하는가&lt;/a&gt;가 변경이 호환되지 않는지 판단하는 테스트를 다룬다. 답이 그렇다면, 두 번째 질문은 수정이 한 줄짜리 편집인지 진짜 마이그레이션인지다. 이름이 바뀐 필드는 호출자가 체인지로그 항목만으로 처리할 수 있다. 인증, 페이지네이션, 오류 처리의 변경은 거의 항상 가이드를 받을 자격이 있는데, 올바른 대체 코드가 한 문장짜리 설명에서는 명확하지 않기 때문이다.&lt;/p&gt;
&lt;h2&gt;마이그레이션 가이드는 무엇을 담아야 하는가&lt;/h2&gt;
&lt;p&gt;다섯 가지이며, 그중 어느 하나라도 건너뛰는 것이 가이드를 호출자가 한 번 읽고 그다음에는 시행착오로 돌아가는 페이지로 만드는 방식이다. 예전 코드를, 실제 프로젝트에서 나타날 그대로 보여준다. 새 코드를, 같은 방식으로 보여준다, 차이에 대한 추상적인 설명이 아니라. 아무것도 바꾸지 않으면 무엇이 깨지는지 명확히 말한다, &amp;quot;아무것도&amp;quot;는 유효하고 흔한 답이지만 호출자는 그래도 그것을 명시적으로 들어야 하기 때문이다. 마이그레이션이 작동했는지 확인하는 방법, 확인할 응답 필드나 상태 코드 같은 것. 그리고 일정. 예전 동작이 언제 작동을 멈추는지, 그 사이에 두 형태가 모두 사용 가능한지.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;## 통화 필드를 float에서 integer로 마이그레이션 (v3.0.0)

이전:
  { &amp;quot;amount&amp;quot;: 19.99 }

이후:
  { &amp;quot;amount&amp;quot;: 1999 }  // 가장 작은 통화 단위(센트)

무엇이 바뀌는가: `amount`는 이제 계정 통화의 가장 작은 단위의
정수다. `amount`를 float으로 읽는 코드는 2026년 10월 1일부터
100배 큰 값을 읽게 된다.

검증: 마이그레이션 후 19.99달러 청구는 `amount: 19.99`가 아니라
`amount: 1999`로 읽혀야 한다.

일정: v2는 2027년 1월 15일까지 계속 float를 반환한다. v3는 출시
시점부터 정수를 반환한다. 두 버전 모두 지금 활성 상태다.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 다섯 가지 각각은 그렇지 않으면 호출자가 추측하거나 지원팀에 물어봐야 할 질문에 답하며, 그것이 바로 마이그레이션 가이드가 실제로 절약하는 비용이다.&lt;/p&gt;
&lt;h2&gt;누가 그것을 써야 하고, 언제 써야 하는가&lt;/h2&gt;
&lt;p&gt;변경을 설계한 사람이, 그것이 출시되는 바로 그 순간에. 일주일 후 티켓에서 그것을 재구성하는 지원팀이 아니다. 결정을 내린 사람은 예전 동작의 어느 부분에 아무도 의존하지 말았어야 했는지, 어느 부분이 우연한 계약이었는지 안다. 그 맥락 없이 나중에 누군가 쓴 가이드는 명백한 것을 과도하게 설명하거나 사람들을 실제로 망가뜨리는 그 하나의 엣지 케이스를 놓치는 경향이 있다. 가이드와 호환되지 않는 변경을 발표하는 체인지로그 항목은 함께 나와야 하며, 항목은 그것을 반복하는 대신 가이드로 링크해야 한다.&lt;/p&gt;
&lt;h2&gt;이것이 버전 관리 및 API 체인지로그와 어떻게 연결되는가&lt;/h2&gt;
&lt;p&gt;직접적으로. 마이그레이션 가이드는 &lt;a href=&quot;https://changeloop.dev/blog/ko/semantic-versioning-changelog/&quot;&gt;시맨틱 버저닝과 당신의 체인지로그&lt;/a&gt;에서 MAJOR 항목이 한 문장으로만 요약하는 것의 상세 버전이다. 체인지로그 항목은 변경이 호환되지 않는다는 것과 대략 무엇이 바뀌었는지 말한다. 마이그레이션 가이드는 그 항목이 담아야 할 링크다. &lt;a href=&quot;https://changeloop.dev/blog/ko/api-changelog/&quot;&gt;API 체인지로그: 무엇을 공개하고 누가 읽는가&lt;/a&gt;는 마이그레이션 가이드를 API가 유지하는 다섯 문서 중 하나로 나열하며, 각각 다른 질문에 답한다. 이것은 &amp;quot;A에서 B로 실제로 어떻게 옮기는가&amp;quot;에 답하는 것이며, 그 답이 보통 체인지로그 항목에는 너무 길기 때문에 정확히 자신만의 페이지를 받을 자격이 있다.&lt;/p&gt;
&lt;h2&gt;마이그레이션 가이드는 얼마나 오래 게시된 상태로 남아 있어야 하는가&lt;/h2&gt;
&lt;p&gt;최소한 예전 동작이 도달 가능한 동안은, 그리고 이상적으로는 그 이후에도. 세 번의 비추천 공지를 무시한 후 열여덟 달 늦게 마이그레이션하는 호출자도 여전히 가이드가 필요하며, 예전 동작이 꺼지는 그날 그것을 삭제하는 것은 그것이 가장 필요한 호출자가 그것을 찾지 못하도록 보장할 뿐이다. 안정적인 URL에 유지하고 페이지를 철회하는 대신 일정 섹션을 업데이트하라. Stripe 자체의
&lt;a href=&quot;https://docs.stripe.com/upgrades&quot;&gt;업그레이드 가이드&lt;/a&gt;가 바로 이 패턴의 공개된 사례다. 릴리스마다
새 문서를 만들어 다음 버전이 나오는 순간 낡아버리게 두는 대신, 페이지 하나를 계속 최신 상태로
유지한다. 여러분의 가이드도 블로그 아카이브에 묻혀 있지 말고, 호출자가 이미 읽고 있는
&lt;a href=&quot;https://changeloop.dev/docs&quot;&gt;문서&lt;/a&gt; 바로 옆처럼 그만큼 찾기 쉬운 곳에 있어야 한다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;모든 호환되지 않는 변경에 마이그레이션 가이드가 필요한가?&lt;/strong&gt;
아니다. 호출자가 체인지로그 항목만으로 해결할 수 있는 변경, 예를 들어 명백한 대체가 있는 이름이 바뀐 필드 하나는 별도의 가이드가 필요 없다. 여러 호출 지점을 건드리거나 작성된 예시가 필요한 변경은 필요하다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;마이그레이션 가이드는 API 문서와 함께 있어야 하는가, 아니면 체인지로그에 있어야 하는가?&lt;/strong&gt;
문서와 함께, 체인지로그 항목에서 링크되어야 한다. 항목은 구독자가 먼저 보는 것이고, 가이드는 행동하기로 결정한 순간 필요한 것이며, 호출자가 이미 사용하고 있는 참조 자료 옆에 속한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;마이그레이션 가이드와 비추천 공지의 차이는 무엇인가?&lt;/strong&gt;
비추천 공지는 무언가가 사라질 것이고 언제까지인지를 선언한다. 마이그레이션 가이드는 그것에 대해 무엇을 할지에 대한 지침이다. 링크된 마이그레이션 가이드가 없는 비추천 공지는 호출자에게 마감일은 주지만 그것을 어떻게 맞출지는 알려주지 않는다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;마이그레이션 기간 동안 예전 동작과 새 동작을 모두 문서화해야 하는가?&lt;/strong&gt;
그렇다, 가능하다면 같은 페이지에. 호출자가 서로 다른 시기에 작성된 두 개의 별도 문서에서 조합하는 대신 정확히 무엇이 바뀌었는지 보게 하기 위해서다.&lt;/p&gt;
</content:encoded></item><item><title>GitHub Actions용 체인지로그 체크</title><link>https://changeloop.dev/blog/ko/changelog-ci-enforcement/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/changelog-ci-enforcement/</guid><description>GitHub Actions 체인지로그 체크는 항목 없는 머지를 막는다. 기억에 의존하면 일정 앞에서 실패하는 이유와 체크 자체가 깨뜨리는 것을 다룬다.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;체인지로그를 수작업으로 유지하는 모든 팀은 같은 사건 뒤에 같은 대화를 나눈 적이 있다. 릴리스가 항목 없이 나갔고, 누군가 왜냐고 묻고, 정직한 답은 그것을 썼을 사람이 바쁘게 움직이고 있었고 체인지로그 단계가 오직 기억 속에만 존재했다는 것이다. &lt;a href=&quot;https://changeloop.dev/blog/ko/changelog-automation/&quot;&gt;체인지로그 자동화&lt;/a&gt;는 파이프라인이 안전하게 자동화할 수 있는 것과 여전히 사람이 필요한 것을 다룬다. CI에서의 체인지로그 체크는 이 문제의 나머지 절반이다. 쓰기를 자동화해도 애초에 아무도 그것을 실행할 의무가 없다면 도움이 되지 않기 때문이다. 대부분의 팀은 이미 풀 리퀘스트 체크를 GitHub Actions에서 돌리고 있으므로, 이 체크도 거기에 자리 잡는다.&lt;/p&gt;
&lt;h2&gt;&amp;quot;사람들에게 항목을 추가해달라고 부탁한다&amp;quot;는 왜 예측 가능한 패턴으로 실패하는가&lt;/h2&gt;
&lt;p&gt;풀 리퀘스트 안의 다른 모든 것과 관심을 두고 경쟁하며, 건너뛰어도 즉각적인 결과가 없는 유일한 부분이기 때문이다. 테스트는 시끄럽게 실패하며 머지를 막는다. 빠진 체인지로그 항목은 아무것도 막지 않으므로, 누군가 서두르는 순간, 실제로는 대부분의 시간에 패배한다. 기억으로 강제되는 정책은 예상할 수 있는 바로 그 속도로 저하된다. 모두가 동의한 첫 몇 주는 괜찮다가, 신경 쓰던 사람이 휴가를 가거나 팀을 옮기는 순간 조용히 버려진다.&lt;/p&gt;
&lt;h2&gt;체인지로그 항목을 위한 CI 체크는 실제로 무엇을 검증하는가&lt;/h2&gt;
&lt;p&gt;글쓰기의 품질이 아니라 항목이 존재하고 형식이 올바른지 여부만이며, 이는 사람의 머릿속이 아니라 CI에서 실행되는 체인지로그 체크에 맞는 범위다. 흔한 형태는, 체크가 PR의 diff를 보고 changeset 디렉터리 안의 새 파일(&lt;a href=&quot;https://github.com/changesets/changesets&quot;&gt;Changesets&lt;/a&gt;와 비슷한 도구들이 쓰는 패턴)이나 체인지로그 파일 안의 변경된 줄 둘 중 하나를 요구하고, 둘 다 없으면 빌드를 실패시킨다. 항목이 실제로 무엇을 말하는지에 대한 검토는 언제나 그래왔던 곳, 즉 코드 리뷰에서 계속 이루어진다. 그 판단은 스크립트가 할 일이 아니기 때문이다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;CI 체크가 검증하는 것&lt;/th&gt;
&lt;th&gt;검증하지 않는 것&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;diff에 changeset이나 체인지로그 줄이 존재한다&lt;/td&gt;
&lt;td&gt;표현이 명확한지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;항목이 모노레포에서 올바른 패키지를 참조한다&lt;/td&gt;
&lt;td&gt;변경이 애초에 항목을 받을 만한지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;파일이 구문적으로 유효하다 (frontmatter, JSON 형태)&lt;/td&gt;
&lt;td&gt;항목이 영향에 대해 정직한지&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;모든 PR이 이것을 필요로 하는가, 아니면 일부 변경은 면제되는가&lt;/h2&gt;
&lt;p&gt;일부는 면제되며, 면제 목록이야말로 이런 시스템이 실제로 구축되거나 버려지는 지점이다. 눈에 띄는 효과가 없는 의존성 업데이트, 테스트만 바뀌는 변경, 동작 변화 없는 내부 리팩터링, 이 중 어느 것도 체인지로그를 읽는 누구도 신경 쓰지 않는 것을 위해 기여자가 체인지로그 항목을 지어내도록 강요해서는 안 된다. 효과적인 패턴은 기여자가 적용할 수 있는(&lt;code&gt;no-changelog-needed&lt;/code&gt;) 라벨이나 플래그이며, 파일 없이 CI 체크를 만족시키고, PR을 승인하는 사람이 검토하므로 면제 자체가 항목이 통과했을 것과 같은 검토를 통과하게 된다.&lt;/p&gt;
&lt;h2&gt;긴급 핫픽스 같은 정당한 예외는 어떻게 되는가&lt;/h2&gt;
&lt;p&gt;게이트는 배포가 아니라 머지에 있다. 진짜 시간 압박 아래 있는 핫픽스는 CI 체크가 완성된 문단이 아니라 의도로 만족되는 한, 자리 표시자 항목이나 후속 티켓으로 머지할 수 있다. 일부 팀은 다음 릴리스 컷 전에 메인테이너가 다듬는 한 줄짜리 스텁을 받아들인다. 게이트가 절대 허용해서는 안 되는 것은 그 단계를 조용히 건너뛰는 것이다. 잊혀진 스텁은 한 번도 존재한 적 없는 항목보다 작은 실패이며, 스텁은 적어도 누군가 나중에 찾을 수 있는 흔적을 남기기 때문이다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# .github/workflows/changelog-check.yml
on:
  pull_request:
    types: [opened, synchronize, reopened, labeled, unlabeled]
jobs:
  changelog:
    if: &amp;gt;-
      !contains(github.event.pull_request.labels.*.name,
      &amp;#39;no-changelog-needed&amp;#39;)
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0 # the diff needs the base branch
      - name: Require changelog entry
        run: |
          base=&amp;quot;origin/${{ github.base_ref }}&amp;quot;
          if ! git diff --name-only &amp;quot;$base&amp;quot;...HEAD \
              | grep -q &amp;#39;^\.changeset/&amp;#39;; then
            echo &amp;quot;No changeset. Add one, or have a maintainer&amp;quot;
            echo &amp;quot;apply the no-changelog-needed label.&amp;quot;
            exit 1
          fi
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;이 체크가 실제 PR을 막기 시작하기 전에, 체크 자체가 올바른지 어떻게 아는가&lt;/h2&gt;
&lt;p&gt;먼저 버릴 수 있는 브랜치를 대상으로 스크래치 풀 리퀘스트를 열어본다. changeset이 있는 것 하나, 없는 것 하나, 면제 라벨을 단 것 하나를 만들어 세 가지 모두 다른 사람의 작업에 이 체크가 적용되기 전에 예상한 결과가 나오는지 확인한다. 조건이 거꾸로 쓰여서 모든 PR을 통과시키는, 즉 실패 개방형 체인지로그 체크는 아예 체크가 없는 것보다 나쁘다. 존재하지 않는 커버리지처럼 보이기 때문이다. 같은 파일에 대해 &lt;code&gt;workflow_dispatch&lt;/code&gt;를 수동으로, 최근에 머지된 PR 몇 개를 대상으로 돌려보는 것만으로도 실제 풀 리퀘스트 없이 이런 실수 대부분을 잡아낼 수 있다.&lt;/p&gt;
&lt;h2&gt;같은 아이디어가 GitHub Actions 바깥에서도 통하는가&lt;/h2&gt;
&lt;p&gt;형태는 그대로 옮겨가고, 문법만 달라진다. GitLab CI는 같은 규칙을 GitHub Actions의 &lt;code&gt;if&lt;/code&gt; 대신 &lt;code&gt;$CI_MERGE_REQUEST_LABELS&lt;/code&gt;를 확인하는 job &lt;code&gt;rules&lt;/code&gt; 블록으로 표현하며, 필수 머지 리퀘스트 승인이 면제 검토 단계를 대신할 수 있다. 이 글이 설명하는 체크가 GitHub Actions인 이유는 이 글을 읽는 대부분의 팀이 이미 그 플랫폼을 쓰고 있기 때문일 뿐, 그 밑에 깔린 요구사항, 즉 부탁받은 관행이 아니라 머신이 검증하는 게이트라는 것은 CI가 머지 전에 돌아가는 모든 곳에서 동일하다.&lt;/p&gt;
&lt;h2&gt;이것은 모노레포에서도 똑같이 작동하는가&lt;/h2&gt;
&lt;p&gt;한 조각이 더 필요하다. 항목이 어느 패키지를 위한 것인가다. &lt;a href=&quot;https://changeloop.dev/blog/ko/monorepo-changelogs/&quot;&gt;모노레포 체인지로그&lt;/a&gt;는 패키지가 독립적으로 릴리스되는 순간 저장소 전체를 위한 단일 파일이 작동을 멈추는 이유를 다룬다. CI 체크는 같은 요구사항을 물려받는다. 패키지를 명시하지 않는 changeset은 올바른 체인지로그가 업데이트될 것이라는 유용한 증거가 아니라, diff 어딘가에서 어떤 파일이 바뀌었다는 증거일 뿐이다. 이를 위해 만들어진 도구들(JavaScript 생태계에서는 Changesets가 흔하다)은 changeset이 만들어지는 바로 그 순간 기여자에게 영향받는 패키지와 semver 상승을 선택하게 하므로, CI 체크는 나중에 추론하는 대신 두 정보를 공짜로 얻는다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;CI 체크는 머지를 막아야 하는가, 아니면 경고만 해야 하는가?&lt;/strong&gt;
막아야 한다. 경고는 기능적으로 정중하게 부탁하는 것과 동일하며, 그것은 이미 실패했다. 면제 라벨은 진짜 경고만 필요한 경우조차 같은 엄격한 게이트를 통과하는 정당한 경로를 갖도록 정확히 그 목적으로 존재한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;면제 라벨이 올바르게 적용되었는지는 누가 검토하는가?&lt;/strong&gt;
PR을 승인하는 사람이, 어차피 이미 하고 있는 검토의 일부로서. 라벨은 절대 스스로 적용되고 검토되지 않은 채 남아서는 안 된다. 그렇지 않으면 게이트가 막으려던 바로 그 조용한 우회로가 되어버린다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CI에서 이를 의무화하는 것이 체인지로그 자동화 파이프라인의 필요성을 대체하는가?&lt;/strong&gt;
아니다, 그것을 먹여 살린다. &lt;a href=&quot;https://changeloop.dev/blog/ko/changelog-automation/&quot;&gt;체인지로그 자동화&lt;/a&gt;는 구조화된 항목을 페이지, 피드, 이메일로 바꾸는 것을 다룬다. CI 체크는 애초에 자동화할 그 구조화된 항목들이 존재하도록 보장하는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;먼저 구축할 가치가 있는 이것의 가장 작은 버전은 무엇인가?&lt;/strong&gt;
지정된 체인지로그 디렉터리 아래 어떤 파일도 변경되지 않았다면 실패하는 단일 체크와, 하나의 면제 라벨이다. 패키지별 라우팅과 모노레포를 위한 semver 추론은 나중에 와도 된다. 핵심 습관, 항목이 존재하거나 누군가 명시적으로 필요 없다고 말했거나, 이것이야말로 첫날부터 가질 가치가 있는 것이다.&lt;/p&gt;
</content:encoded></item><item><title>고객을 잃지 않고 기능 요청을 거절하는 방법은 무엇인가</title><link>https://changeloop.dev/blog/ko/declining-feature-requests/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/declining-feature-requests/</guid><description>루프를 닫는다는 것은 보통 요청이 출시되었다고 알리는 일이다. 더 어려운 쪽은 관계를 해치지 않고 거절하는 일이며, 좋은 거절이 말해야 할 것을 설명한다.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;순환을 닫는다는 것은 보통 누군가에게 그들의 요청이 출시되었다고 말하는 것을 의미한다. 대부분의 추적 시스템이 전혀 절차를 갖고 있지 않은 더 어려운 절반은 거절하는 것이다. 대부분의 기능 요청은 절대 출시되지 않으며, 이는 제품이 사용자에게 실제로 빚지고 있는 순환 닫기의 대부분이 발표가 아니라 거절이라는 뜻이고, 잘못 처리된 거절은 침묵이 들었을 것보다 더 많은 호의를 잃게 만든다. 잘 처리하면 거의 아무것도 들지 않을 수 있는데, 요청한 사람이 대부분의 경우 가장 원하는 것이 기능 자체가 아니라 자신이 들렸다는 것을 아는 것이기 때문이다.&lt;/p&gt;
&lt;h2&gt;왜 잘 거절하는 것이 잘 출시하는 것만큼 중요한가&lt;/h2&gt;
&lt;p&gt;침묵은 설명 없는 거절로 읽히고, 설명된 거절은 관심으로 읽히기 때문이다. 아무것도 듣지 못한 사람은 요청이 무시되었거나 사라졌다고 추측하며, 두 결론 모두 그녀에게 다시 묻는 수고를 그만두도록 가르친다. 이는 진짜 거절에서 제품이 얻는 것과 같은 결과이며, 다만 더 느리게 도달하고 그 과정에 더 많은 원망이 따를 뿐이다. 명확하게, 이유와 함께 거절한다고 말하는 답변은 출시된 기능만큼이나 완전하게 순환을 닫으며, 그것을 더 빨리 해낸다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;답변&lt;/th&gt;
&lt;th&gt;요청한 사람이 배우는 것&lt;/th&gt;
&lt;th&gt;관계에 드는 비용&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;침묵&lt;/td&gt;
&lt;td&gt;아무도 읽지 않았거나 아무도 신경 쓰지 않는다&lt;/td&gt;
&lt;td&gt;높음, 미래의 모든 요청마다 쌓인다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;이유 없는 자동 답변&lt;/td&gt;
&lt;td&gt;어딘가 무기한 대기열에 있다&lt;/td&gt;
&lt;td&gt;중간, 시간은 벌지만 신뢰는 못 번다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;이유 있는 거절&lt;/td&gt;
&lt;td&gt;읽혔고, 고려되었고, 답변되었다&lt;/td&gt;
&lt;td&gt;낮음, 이유가 정직하다면&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;대안 있는 거절&lt;/td&gt;
&lt;td&gt;진짜 필요가 정말로 들렸다&lt;/td&gt;
&lt;td&gt;가장 낮음, 종종 신뢰를 쌓는다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;무엇이 거절을 나쁘게 착지시키는가&lt;/h2&gt;
&lt;p&gt;거의 항상 세 가지가 결합되어서다. 일반성. 실제로 무엇을 요청했는지 언급하지 않는 정형화된 &amp;quot;피드백 감사합니다&amp;quot;는, 실제로 읽었더라도 전혀 읽지 않은 것처럼 읽힌다. 지연. 요청한 사람이 이미 물어봤다는 것을 잊은 후, 요청으로부터 6개월 후에 도착하는 거절은 빠른 거절보다 더 나쁘게 느껴지는데, 요청이 고려되고 거절된 것이 아니라 손대지 않은 채 방치되었음을 암시하기 때문이다. 그리고 버티지 못하는 이유. &amp;quot;저희 로드맵에 없습니다&amp;quot;는 아무것에도 답하지 않는 반면, &amp;quot;이것은 권한이 작동하는 방식을 재설계해야 하는데, 저희는 올해 그것을 건드릴 계획이 없습니다&amp;quot;는 요청한 사람에게 실제로 평가할 수 있고, 충분히 중요하다면 에스컬레이션하거나 우회할 수 있는 무언가를 준다.&lt;/p&gt;
&lt;h2&gt;좋은 거절은 실제로 무엇을 말해야 하는가&lt;/h2&gt;
&lt;p&gt;이 순서대로 네 가지. 일반적인 바꿔 말하기가 아니라 구체적인 요청을 명명하는 인정. 진짜 이유, 정직한 이유가 더 부드러운 변명 대신 &amp;quot;이것은 제품이 향하는 방향에 맞지 않습니다&amp;quot;일 때도 정직하게 진술된 것. 문이 닫혔는지 아니면 지금은 그냥 열려 있지 않은 것인지, 이것은 매우 다른 톤을 필요로 하기 때문이다. 그리고 존재한다면, 문자 그대로 요청된 기능이 아니더라도 근본적인 필요를 다루는 대안.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;안녕하세요 Jamie,

팀 초대를 위한 대량 CSV 가져오기 추가 요청 감사합니다. 검토했지만,
저희는 이것을 만들지 않을 것입니다: 저희 초대 흐름은 보안상의
이유로 각 신규 구성원을 개별적으로 검토하는 것을 중심으로
설계되어 있고, 대량 가져오기는 실수가 아니라 설계상 그것에
어긋납니다.

만약 진짜 문제가 큰 팀을 빠르게 초대하는 것이라면, API는 스크립트로
작성된 개별 초대를 지원하며, 검토를 우회하지 않고도 거의 모든
속도를 제공합니다: [링크]. 설정하는 데 도움이 필요하면 알려주세요.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이것이 템플릿이 할 수 없는 것을 하고 있다는 점에 주목하라: 실제 기능을 명명하고, 모호한 정책 대신 실제 설계 결정에 연결된 이유를 제공하며, 티켓을 닫기만 하는 대신 근본적인 문제를 해결하는 경로를 제시한다.&lt;/p&gt;
&lt;h2&gt;이것이 출시된 기능에서 순환을 닫는 것과 어떻게 다른가&lt;/h2&gt;
&lt;p&gt;메커니즘은 비슷하지만 톤은 다르다. &lt;a href=&quot;https://changeloop.dev/blog/ko/customer-feedback-loop/&quot;&gt;고객과의 피드백 순환 닫기&lt;/a&gt;가 출시된 경우를 다루는데, 거기서 메시지는 좋은 소식이고 주요 위험은 보내는 것을 잊는 것이다. 거절은 나쁜 소식이거나, 적어도 원하지 않은 소식이며, 주어지는 이유에 더 많은 주의가 필요하고 전달에서 자동화는 덜 필요하다. 출시된 기능 알림은 상태 변경으로 촉발되는 정형화된 댓글일 수 있지만, 정형화된 것처럼 읽히는 거절은 이 접근 전체가 피하려는 바로 그 실패 방식이다. 그래도 둘 다 하나의 요구사항을 공유한다: 원래 요청은 그것을 만든 사람과 계속 연결되어 있어야 하며, 이는 &lt;a href=&quot;https://changeloop.dev/blog/ko/feature-request-tracking/&quot;&gt;기능 요청 추적&lt;/a&gt;이 다루는 것과 같은 추적 원칙이다, 그렇지 않으면 두 메시지 중 어느 쪽도 개별적으로 보낼 방법이 없다.&lt;/p&gt;
&lt;h2&gt;거절은 공개 로드맵의 상태처럼 공개되어야 하는가&lt;/h2&gt;
&lt;p&gt;보통 구체적인 이유는 아니지만, 상태는 그럴 수 있다. &lt;a href=&quot;https://changeloop.dev/blog/ko/public-roadmap/&quot;&gt;공개 로드맵&lt;/a&gt;이 요청한 사람이 다시 묻지 않고 확인할 수 있는 상태 라벨을 다루며, &amp;quot;거절됨&amp;quot;이나 &amp;quot;계획 없음&amp;quot; 상태는 그 시스템의 일부가 될 수 있다. 하지만 상세한 이유는, 특히 내부 우선순위나 그다지 좋지 않은 맥락을 건드릴 때, 보통 공개 상태 페이지보다 개별 답변에서 더 가치 있다, 거기서는 같은 표현이 실제로 물어본 그 한 사람이 아니라 모든 독자에게 통해야 하기 때문이다.&lt;/p&gt;
&lt;h2&gt;거절된 모든 요청이 개별 답변을 받을 자격이 있는가&lt;/h2&gt;
&lt;p&gt;이름이 있고 연락 가능한 사람의 모든 요청은 그렇다, 적어도 짧게라도. 대량, 중복, 익명 요청은 예외다: 비슷한 요청을 그룹화하고 그룹당 한 번 답변하거나 공유된 상태 라벨을 업데이트하는 것은 개별 답변이 정말로 확장되지 않을 때 합리적이다. 지켜야 할 선은 &amp;quot;모두에게 개별적으로 답변할 수 없습니다&amp;quot;가 실제 물량에 대비해 확인된 진짜 운영상의 제약이어야 한다는 것이지, 2분이면 끝났을 답변을 건너뛰기 위한 기본 변명이어서는 안 된다는 것이다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;약한 이유로 빠르게 거절하는 것과 좋은 이유를 위해 시간을 들이는 것 중 어느 쪽이 나은가?&lt;/strong&gt;
정직한 이유로 빠르게 하는 것이 둘 다 따로따로 이기는 것보다 낫다. 짧더라도 진짜 이유가 있는 빠른 답변이, 다듬어진 이유가 있는 느린 답변보다 낫다. 지연 자체가 신뢰를 해치는 요소의 일부다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;거절이 나중에 요청을 재고하겠다고 약속해야 하는가?&lt;/strong&gt;
그것이 정말로 가능성이 있고 실제로 재고할 메커니즘이 있을 때만, 예를 들어 계획 주기에서 그것을 다시 떠오르게 하는 라벨 같은 것. 그런 메커니즘 없는 모호한 &amp;quot;염두에 두겠습니다&amp;quot;는 기능적으로 침묵과 같으며, 다만 더 친절하게 표현되었을 뿐이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;정직한 이유가 경쟁상의 우려처럼 회사가 공유할 수 없는 것이라면 어떻게 해야 하는가?&lt;/strong&gt;
더 부드러운 이유를 지어내는 대신 그것을 직접 말하라. &amp;quot;여기서 구체적인 근거를 공유할 수는 없지만, 이것은 저희가 만들 계획이 있는 것이 아닙니다&amp;quot;가 후속 질문에서 무너지는 지어낸 설명보다 더 정직하고 더 존중받는다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;요청을 거절하는 것이 추적에서 삭제해야 한다는 뜻인가?&lt;/strong&gt;
아니다. 이유와 함께 거절됨으로 라벨을 붙여 보관하라, 그것이 다음 비슷한 요청이 그룹화되는 패턴의 일부가 되도록, 그리고 나중에 바뀐 맥락(새 통합, 새 팀 우선순위)이 평가를 처음부터 다시 시작하는 대신 그것을 다시 떠오르게 할 수 있도록.&lt;/p&gt;
</content:encoded></item><item><title>기능 요청을 놓치지 않고 추적하는 방법</title><link>https://changeloop.dev/blog/ko/feature-request-tracking/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/feature-request-tracking/</guid><description>기능 요청 추적은 어디에도 도달하지 못하거나 아무도 보지 않는 곳에 쌓여서 실패한다. 두 실패를 견디는 체계와 쓸모 있는 라벨 붙이는 법을 설명한다.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;기능 요청 추적은 거의 항상 두 가지 방식 중 하나로 실패한다. 요청이 갈 곳이 없어서 받은편지함과 슬랙 스레드에 살다가 하나씩 잊히거나, 갈 곳은 있지만 아무도 다시 들여다보지 않아서 한꺼번에 잊힌다. 작동하는 체계는 이 두 실패를 모두 견뎌내야 한다. 모든 요청이 도착하는 하나의 장소와, 다음 달에 그 장소를 다시 열어볼 이유가 필요하다.&lt;/p&gt;
&lt;h2&gt;기능 요청은 실제로 어디서 오는가&lt;/h2&gt;
&lt;p&gt;대부분의 추적 체계가 고려하는 것보다 더 많은 채널에서 온다. &amp;quot;이런 게 있으면 좋겠다&amp;quot;가 담긴 지원 티켓. 공개 로드맵에 달린 댓글. 잠재 고객이 거래를 막는 바로 그 한 가지를 언급하는 영업 통화. 제품 안의 위젯. 각 채널에는 각자의 담당자와 각자의 도구가 있으며, 바로 그래서 요청이 흩어진다. 지원 티켓 큐와 제품팀 백로그는 같은 체계인 경우가 드물고, 둘 중 하나에만 도달한 요청은 실제로는 부서 하나에만 도달한 것이다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;출처&lt;/th&gt;
&lt;th&gt;일반적인 담당자&lt;/th&gt;
&lt;th&gt;대개 사라지는 곳&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;지원 티켓&lt;/td&gt;
&lt;td&gt;지원팀&lt;/td&gt;
&lt;td&gt;해결됨으로 종료되고 다시 검토되지 않음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;영업 통화&lt;/td&gt;
&lt;td&gt;영업 / 계정 관리&lt;/td&gt;
&lt;td&gt;제품팀 누구도 읽지 않는 CRM 필드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;제품 내 위젯&lt;/td&gt;
&lt;td&gt;제품&lt;/td&gt;
&lt;td&gt;후속 조치 없는 폼 제출&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;로드맵 댓글&lt;/td&gt;
&lt;td&gt;로드맵을 만든 사람&lt;/td&gt;
&lt;td&gt;댓글 스레드 자체&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;소셜 미디어 / 리뷰&lt;/td&gt;
&lt;td&gt;마케팅 또는 아무도&lt;/td&gt;
&lt;td&gt;한 번 캡처되고 사라짐&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;채널마다 하나씩의 인테이크 폼은 작동하지 않는다, 아무도 채택하지 않기 때문이다. 작동하는 것은 모든 채널이 흘러드는 하나의 목적지다, 라우팅이 자동화되기 전까지는 하루 5분의 복사 붙여넣기를 사람이 처리하는 방식이더라도.&lt;/p&gt;
&lt;h2&gt;기능 요청 추적을 실제로 망가뜨리는 것은 무엇인가&lt;/h2&gt;
&lt;p&gt;거의 항상 두 가지다. 첫째는 목적지의 부재다. 요청은 도착한 채널에서 답변을 받고 어디에도 지속적으로 기록되지 않아서, 세 명의 다른 고객에게서 온 같은 요청이 하나의 신호가 아니라 세 개의 고립되고 무관한 일회성 답변처럼 보인다. 둘째, 더 흔한 것은 가득 차서 더 이상 읽히지 않는 목적지다. 필터링되지 않은 400행짜리 스프레드시트는 더 이상 추적 체계가 아니다. 우연히 편집 가능한 보관소일 뿐이다.&lt;/p&gt;
&lt;p&gt;두 번째 실패가 더 위험하다. 추적이 작동하는 것처럼 보이기 때문이다. 요청은 기록된다. 누군가 &amp;quot;몇 명이 X를 요청했나&amp;quot;라고 물을 때까지는 아무것도 고장 나 보이지 않으며, 정직한 답은 &amp;quot;알려면 400행을 전부 읽어야 한다&amp;quot;이다.&lt;/p&gt;
&lt;h2&gt;기능 요청은 실제로 무엇을 기록해야 하는가&lt;/h2&gt;
&lt;p&gt;나중에 원본 메시지를 다시 읽지 않고도 세 가지 질문에 답할 수 있을 만큼이다. 무엇을 요청했는지, 가능하면 요청한 사람 본인의 말로. 누가 요청했는지, 그리고 답이 결국 &amp;quot;우리가 만들었다&amp;quot;가 된다면 어떻게 연락할지. 그리고 이것이 흔한 요청인지 일회성 사례인지 알려면 무엇이 필요한지. 직접 인용은 바꿔 쓴 것보다 더 가치 있다. 요청을 분류한 사람이 쓴 바꿔 쓴 문장은 이미 그 사람 자신의 해석을 담고 있으며, 바로 그 해석이야말로 여섯 달 후 두 번째 사람이 확인할 수 없는 것이기 때문이다.&lt;/p&gt;
&lt;h2&gt;어떤 라벨이 가치 있는가&lt;/h2&gt;
&lt;p&gt;두 가지가 있고, 서로 다른 질문에 답한다. &lt;strong&gt;유형&lt;/strong&gt; 라벨은 기능 요청을 버그 신고와 분리한다. 둘 다 다른 담당자와 다른 일정이 필요하며, 하나의 큐에 섞으면 가장 시끄러운 불만이 요청을 앞지르게 된다. low, medium, high 같은 작은 집합으로 유지되는 &lt;strong&gt;우선순위&lt;/strong&gt; 라벨은 &amp;quot;누군가 제품을 사용하는 것을 막는다&amp;quot;와 &amp;quot;있으면 좋겠다&amp;quot;를 분리한다. 둘 다 매우 다른 응답 시간을 받을 만하며, 어느 쪽도 다른 쪽의 속도를 물려받아서는 안 되기 때문이다. &lt;strong&gt;유형&lt;/strong&gt; 라벨을 올바르게 붙이는 것은 그 요청이 스스로 주장하는 그대로라고 가정한다. &lt;a href=&quot;https://changeloop.dev/blog/ko/feature-request-vs-bug-report/&quot;&gt;기능 요청이 실제로는 버그 신고일 때&lt;/a&gt;는 고객 자신의 말이 그 라벨을 엉뚱한 방향으로 향하게 하는 경우를 다룬다.&lt;/p&gt;
&lt;p&gt;자동 분류는 요청이 도착하는 순간 둘 다 적용할 수 있다. changeloop에서는 위젯 제출이 같은 단계에서 &lt;code&gt;feature-request&lt;/code&gt; 또는 &lt;code&gt;bug&lt;/code&gt; 라벨과 &lt;code&gt;priority:low|medium|high&lt;/code&gt; 라벨을 받고, 항목을 열지 않아도 출처가 보이도록 &lt;code&gt;from-widget&lt;/code&gt; 태그가 붙는다. 이것만으로 오후 내내가 아니라 1분 만에 백로그를 필터링할 수 있다. 이번 달 위젯에서 온 우선순위 높은 기능 요청을 전부 보여달라는 식으로.&lt;/p&gt;
&lt;p&gt;세 번째 라벨은 공개 로드맵이 생기는 순간 가치가 있다. 요청한 사람이 스스로 확인할 수 있는 상태다. &lt;a href=&quot;https://changeloop.dev/blog/ko/public-roadmap/&quot;&gt;공개 로드맵&lt;/a&gt;이 planned, building, shipped 상태를 완전히 다룬다. 짧게 말하면, 이 라벨은 비공개 큐를 요청한 사람이 다시 묻지 않고도 확인할 수 있는 것으로 바꾼다.&lt;/p&gt;
&lt;h2&gt;다음에 무엇을 만들지는 어떻게 결정하는가&lt;/h2&gt;
&lt;p&gt;세기 전에 먼저 묶어라. 같은 근본 기능에 대해 서로 다르게 표현된 열 개의 요청은 스프레드시트에 흩어진 열 개의 행처럼 읽히지만, 묶으면 강한 신호가 된다. 그 묶음이 대개 빠진 단계이지 세는 것이 아니다. 묶지 않은 원시 개수는 뒤에 있는 실제 수요가 가장 큰 기능이 아니라 가장 눈에 띄는 이름을 가진 기능에 보상하는 경향이 있다.&lt;/p&gt;
&lt;p&gt;몇 명이 요청했는지가 아니라 누가 요청했는지로 가중치를 둬라. 갱신이 임박한 계정의 요청은 체험판 가입의 같은 요청과는 다른 긴급성을 지니며, 이 맥락을 벌거벗은 숫자를 위해 버리는 추적 체계는 가장 유용한 숫자가 아니라 가장 계산하기 쉬운 숫자에 최적화하는 것이다.&lt;/p&gt;
&lt;p&gt;여기서의 모든 결정은 지는 요청도 만들어내며, 그것들도 답변을 받을 자격이 있다; &lt;a href=&quot;https://changeloop.dev/blog/ko/declining-feature-requests/&quot;&gt;기능 요청을 거절하는 방법&lt;/a&gt;이 성사되지 않은 요청을 한 사람에게 무엇을 말해야 하는지를 다룬다. 그룹으로 묶고 가중치를 매기는 것은 &amp;quot;다음에 무엇을 만들 것인가&amp;quot;의 절반일 뿐이다; &lt;a href=&quot;https://changeloop.dev/blog/ko/prioritizing-feature-requests/&quot;&gt;기능 요청 우선순위&lt;/a&gt;가 실제 프레임워크, RICE, 매출 가중, 순수 요청 수, 그리고 각각이 어디서 무너지는지를 다룬다.&lt;/p&gt;
&lt;h2&gt;무언가 출시되면 어떻게 순환을 닫는가&lt;/h2&gt;
&lt;p&gt;이것은 추적 체계가 가장 자주 건너뛰는 단계이며, 요청한 사람이 실제로 알아채는 단계다. &lt;a href=&quot;https://changeloop.dev/blog/ko/customer-feedback-loop/&quot;&gt;고객과의 피드백 순환 닫기&lt;/a&gt;가 그 메커니즘을 완전히 다룬다. 여기서 중요한 것은 원래 요청이 요청한 사람과 계속 연결되어 있을 때만 순환 닫기가 작동한다는 점이다. GitHub 이슈에서 만들어진 기능 요청 템플릿으로, 요청한 사람의 신원이 댓글에 묻히지 않고 이슈 자체에 붙어 있는 것이 누군가 기억해서 보내야 하는 알림 대신 자동 &amp;quot;출시됨&amp;quot; 알림을 가능하게 만드는 것이다. &lt;a href=&quot;https://changeloop.dev/blog/ko/feature-request-template/&quot;&gt;기능 요청 템플릿&lt;/a&gt;이 구체적인 템플릿과 각 필드가 무엇을 위한 것인지 보여준다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;기능 요청 추적에는 어떤 도구를 써야 하는가?&lt;/strong&gt;
팀이 이미 매일 확인하는 것이 아무도 열지 않는 전용 도구를 이긴다. 엔지니어링이 이미 거기 있다면 GitHub 이슈 트래커가 잘 작동하고, 제품팀이 거기 있다면 가벼운 보드가 잘 작동한다. 도구 자체보다 다시 열어보는지 여부가 더 중요하다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;기능 요청이 중복되는 것을 어떻게 막는가?&lt;/strong&gt;
표현으로 분류하기 전에 근본 기능으로 묶어라. 새로 만들기 전에 기존 요청을 검색하면 대부분의 중복을 잡아낸다. 매달 한 번의 묶음 작업이 나머지를 잡아낸다.
&lt;a href=&quot;https://changeloop.dev/blog/ko/duplicate-feature-requests/&quot;&gt;원래 목소리를 잃지 않고 중복 병합하기&lt;/a&gt;는 묶음 자체가 끝난 후 표현을 어떻게 처리해야 하는지 다룬다, 그래서 병합이 먼저 도착한 제출로 요청을 조용히 좁히지 않도록.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;모든 기능 요청이 답변을 받아야 하는가?&lt;/strong&gt;
모든 요청은 짧더라도 확인을 받아야 하지만, 모두가 즉시 결정을 필요로 하는 것은 아니다. 요청한 사람이 스스로 확인할 수 있는 로드맵 라벨 같은 보이는 상태가, 팀이 그렇지 않으면 개별적으로 해야 했을 대부분의 답변을 대체한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;기능 요청 추적과 공개 로드맵의 차이는 무엇인가?&lt;/strong&gt;
추적은 절대 출시되지 않을 것들을 포함해 모든 요청의 내부 기록이다. 공개 로드맵은 팀이 공개적으로 약속하는 부분집합으로, 요청한 사람이 다시 묻지 않고도 볼 수 있는 상태를 동반한다.&lt;/p&gt;
</content:encoded></item><item><title>기능 요청이 실제로는 버그 신고일 때</title><link>https://changeloop.dev/blog/ko/feature-request-vs-bug-report/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/feature-request-vs-bug-report/</guid><description>새 설정을 요청하는 지원 티켓은 숨겨진 버그를 우회하는 방법일 수 있다. 잘못된 라벨은 티켓을 엉뚱한 담당자와 대기열로 보낸다. 구별법과 판단할 사람을 다룬다.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;quot;내보내기 한도를 늘리는 설정을 추가해줄 수 있나요&amp;quot;는 기능 요청처럼 읽히고, 대부분의 분류 시스템은 그 자리에서 그렇게 라벨을 붙인다. 때로는 정말 그렇다. 때로는 내보내기가 버그 때문에 문서화된 한도보다 낮은 숫자에서 실패하고 있으며, 코드를 볼 수 없는 고객은 설명할 수 있는 가장 그럴듯한 해결책을 지어낸다. 더 큰 숫자를 주면 어쩌면 작동할지도 모른다는 식으로. &lt;a href=&quot;https://changeloop.dev/blog/ko/feature-request-tracking/&quot;&gt;어떤 라벨이 가치 있는가&lt;/a&gt;는 백로그를 기능 요청과 버그로 나누는 유형 라벨을 다룬다. 이것은 고객 자신의 말이 그 라벨을 엉뚱한 방향으로 향하게 하는 경우이며, 잘못 판단한 대가는 아래를 들여다보면 아무도 정말로 원하지 않는 요청들로 가득 찬 백로그로 서서히 흘러가는 것이다.&lt;/p&gt;
&lt;h2&gt;실제로는 버그인 기능 요청은 어떤 모습인가&lt;/h2&gt;
&lt;p&gt;문제 대신 우회 방법을 지목한다. 진짜 기능 요청은 보통 제품이 전혀 지원하지 않는 결과를 설명한다. &amp;quot;이걸 나중으로 예약할 수 있게 해달라&amp;quot;, &amp;quot;다크 모드를 추가해달라&amp;quot; 같은 식이다. 잘못 분류된 버그는 빠진 설정처럼 들리지만 실제로는 증상인 구체적인 숫자, 임계값, 동작을 설명한다. &amp;quot;타임아웃을 늘려달라&amp;quot;, &amp;quot;재시도 옵션을 추가해달라&amp;quot;, &amp;quot;한 번에 더 많은 행을 내보내게 해달라&amp;quot; 같은 식이다. 신호는 요청자가 목표를 설명하는 대신 구현, 설정, 스위치, 오버라이드를 제안한다는 점이다. 이미 문서대로 그 기능을 시도해봤고, 문서가 해야 한다고 말하는 것을 하지 않았기 때문이다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;신호&lt;/th&gt;
&lt;th&gt;기능 요청&lt;/th&gt;
&lt;th&gt;기능 요청으로 위장한 버그&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;요청자가 설명하는 것&lt;/td&gt;
&lt;td&gt;제품이 할 수 없는 결과&lt;/td&gt;
&lt;td&gt;바꾸고 싶은 매개변수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;문서화된 동작이 이미 이것을 다루는가&lt;/td&gt;
&lt;td&gt;아니오, 정말로 빠져 있다&lt;/td&gt;
&lt;td&gt;예, 하지만 문서대로 작동하지 않는다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;더 많은 노력이 요청을 사라지게 하는가&lt;/td&gt;
&lt;td&gt;아니오&lt;/td&gt;
&lt;td&gt;때로는, 버그가 임계값에 의존한다면&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;어디로 라우팅되어야 하는가&lt;/td&gt;
&lt;td&gt;제품 백로그&lt;/td&gt;
&lt;td&gt;버그 큐&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;이것이 왜 보이는 것보다 더 중요한가&lt;/h2&gt;
&lt;p&gt;두 큐는 다른 담당자, 일정, 성공 기준을 가지며, 기능 요청으로 등록된 버그는 기능 요청들에 대해 우선순위가 매겨져, 버그가 받아야 할 일정에 고쳐지는 대신 진짜 제품 공백과 관심을 두고 경쟁하기 때문이다. &lt;a href=&quot;https://changeloop.dev/blog/ko/feature-request-tracking/&quot;&gt;기능 요청을 추적하는 방법&lt;/a&gt;은 버그와 기능을 하나의 큐에 섞는 것이 왜 가장 시끄러운 불만이 진짜 요청을 앞지르게 하는지를 다룬다. 몰래 버그인 기능 요청은 반대 방향의 피해를 준다. 근본 버그가 고쳐지는 순간 사라질 &amp;quot;기능&amp;quot;에 대한 표를 모으며 제품 백로그에 계속 머물러, 그 백로그를 읽는 모두에게 우선순위 신호를 낭비하게 만든다.&lt;/p&gt;
&lt;h2&gt;고객 자신의 말이 엉뚱한 방향을 가리킬 때 어떻게 구별하는가&lt;/h2&gt;
&lt;p&gt;무엇을 추가해달라고 하는지가 아니라, 무슨 일이 일어날 것으로 기대했는지 물어라. &amp;quot;내보내기가 500행에서 막혔고 2,000행이 필요한데 한도를 올려줄 수 있나요&amp;quot;는 후속 질문 &amp;quot;500이 문서화된 한도인가요&amp;quot;가 문서화된 숫자는 5,000이었고 내보내기가 일찍 실패하고 있다는 것을 밝혀낼 때까지는 한도 상승 기능 요청처럼 들린다. 무엇을 기대했는지 대 무엇이 일어났는지, 그 한 가지 질문만으로 분류 작업의 대부분이 끝난다. 진짜 기능 요청에는 미치지 못하는 문서화된 동작이 애초에 없기 때문이다. 아직 그 능력 자체가 존재하지 않으므로 기대할 것이 없다.&lt;/p&gt;
&lt;h2&gt;지원 담당자와 엔지니어 중 누가 이것을 결정해야 하는가&lt;/h2&gt;
&lt;p&gt;지원 담당자가 티켓을 먼저 보므로 첫 번째 검토를 하지만, 라벨은 바꾸기 쉽고 틀려도 비용이 적어야 하며, 그 항목을 영원히 잘못된 큐에 고정시키는 일회성 결정이어서는 안 된다. 매주 새로운 &amp;quot;기능 요청&amp;quot; 라벨을 훑어보며 위장한 버그 냄새가 나는 것을 찾는 엔지니어라는 가벼운 이차 점검은, 코드베이스 맥락이 없는 지원 담당자가 알아볼 수 없었던 것들을 잡아낸다. 이것이 공식적일 필요는 없으며, 검토 프로세스라기보다 5분짜리 훑어보기에 가깝다.&lt;/p&gt;
&lt;h2&gt;진짜 버그를 찾은 후 순환을 닫는 방식이 바뀌는가&lt;/h2&gt;
&lt;p&gt;그렇다, 그리고 보낼 수 있는 메시지가 개선된다. &lt;a href=&quot;https://changeloop.dev/blog/ko/customer-feedback-loop/&quot;&gt;고객 피드백 순환 닫기&lt;/a&gt;는 요청이 출시될 때 요청자에게 알리는 것을 다룬다. 재분류된 버그는 그 메시지의 더 나은 버전을 얻는다. &amp;quot;이 뒤에 있는 버그를 찾아서 고쳤습니다&amp;quot;는 유능함처럼 들리는 반면, &amp;quot;요청하신 기능을 만들었습니다&amp;quot;는 오직 우연으로만 사실이었을 것이기 때문이다. 진짜 기능 요청, 즉 실제로 더 높은 내보내기 한도는 버그가 사라지고 원래의 5,000행 한도로 충분해지면 결코 만들어지지 않을 수도 있다.&lt;/p&gt;
&lt;h2&gt;잘못된 분류가 한 번도 발견되지 않으면 어떻게 되는가&lt;/h2&gt;
&lt;p&gt;백로그는 진짜 수요처럼 보이지만 그렇지 않은 요청들로 채워지고, 그 백로그에 대해 내려지는 우선순위 결정은 왜곡을 물려받는다. 표 마흔 개짜리 &amp;quot;기능&amp;quot;은 실제로는 같은 버그에 부딪힌 마흔 명일 수 있으며, 문자 그대로의 요청, 즉 실제로는 한 번도 진짜 제약이 아니었던 한도를 올리는 설정을 만드는 것은 아무것도 고치지 못하는 복잡성을 전달하는 동안, 근본 버그는 아직 이 스레드를 찾지 못한 고객들로부터 새로운 &amp;quot;기능 요청&amp;quot;을 계속 만들어낸다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;모든 기능 요청을 알려진 버그와 대조하는 공식 단계를 추가할 가치가 있는가?&lt;/strong&gt;
공식 단계가 아니라 습관에 가깝다. 새 기능 요청을 분류하는 사람은 라벨을 적용하기 전에 &amp;quot;문서화된 동작이 이미 이걸 한다고 주장하는가&amp;quot;를 물어야 한다. 그 한 가지 질문만으로도 프로세스 부담을 늘리지 않고 대부분의 잘못된 분류를 잡아내기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;버그를 찾은 후에도 고객이 기능 요청이라고 계속 주장하면 어떻게 하는가?&lt;/strong&gt;
무엇을 찾았는지, 그리고 버그가 고쳐지면 고객이 제안한 설정이 더 이상 필요하지 않을 이유를 설명하라. 대부분의 고객은 진짜 수정이 불가능하다고 짐작했기 때문에 우회 방법을 요청하는 것이지, 특별히 그 설정을 원해서가 아니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;재분류된 항목은 기능 요청으로 모은 표나 댓글을 잃는가?&lt;/strong&gt;
보이게 유지해야 한다. 그 표들은 애초에 버그를 찾게 만든 증거이며, 그 흔적을 숨기면 다음번에 다른 티켓에서 같은 잘못된 분류를 잡아내기 더 어려워지기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;이것이 반대로도 일어날 수 있는가, 실제로는 기능 요청인 버그 신고는?&lt;/strong&gt;
덜 흔하지만 그렇다. &amp;quot;이게 고장 났다&amp;quot;는 때로 &amp;quot;이게 제가 짐작했던 대로 작동하지 않는다&amp;quot;는 뜻이며, 이는 결함이 아니라 빠진 능력이다. 무엇을 기대했는지 대 무엇이 문서화되어 있는지, 같은 질문이 이 방향으로도 분류한다.&lt;/p&gt;
</content:encoded></item><item><title>피처 플래그 릴리스 노트: 무엇을, 언제 말하는가</title><link>https://changeloop.dev/blog/ko/feature-flags-feature-requests/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/feature-flags-feature-requests/</guid><description>피처 플래그 릴리스 노트는 머지와 출시를 구분해야 한다. 잘못된 시점에 루프를 닫으면 사용자가 아직 볼 수 없는 기능을 알리게 된다. 판단 기준을 짚어본다.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;기능 요청에서 루프를 닫는다는 것은 그것이 출시된 깔끔한 순간이 있다고 가정한다. 피처 플래그는 그 순간을 없애버리고, 바로 그 점이 피처 플래그 릴리스 노트의 타이밍을 어렵게 만든다. 코드는 머지되고, 플래그는 존재하며, 그 이후 며칠에서 몇 주 동안 그 기능은 프로덕션에서 동시에 살아 있으면서 그것을 쓰고 싶어 할 거의 모든 사람에게, 종종 애초에 요청했던 바로 그 사람에게조차 보이지 않는다. 너무 일찍 알리면 아직 존재하지 않는 기능과 마주치게 된다. 너무 늦게 알리면 신뢰를 쌓아야 했을 루프가 대신 잊힌 것처럼 읽힌다.&lt;/p&gt;
&lt;h2&gt;왜 플래그는 &amp;quot;출시하고, 알린다&amp;quot;라는 평소의 순서를 깨뜨리는가&lt;/h2&gt;
&lt;p&gt;하나의 사건을 최소 두 개로 나누기 때문이다. 코드가 라이브가 되는 것과, 특정 계정에 대해 플래그가 켜지는 것이다. 피드백 루프를 닫는 모든 프로세스는 이 둘이 함께 일어난다고 가정하는데, 이는 대부분의 릴리스에는 맞지만 단계적 출시, 타겟팅, 또는 긴급 차단 스위치로 쓰이는 플래그 뒤에 있는 모든 것에는 틀렸다. &lt;a href=&quot;https://changeloop.dev/blog/ko/customer-feedback-loop/&quot;&gt;고객 피드백 루프 닫기&lt;/a&gt;는 체인지로그 항목이 승인되고 게시되는 바로 그 순간에 요청자에게 알리는 것을 설명한다. 그 단계는 항목 게시와 기능 사용 가능이 같은 순간인 경우를 위해 쓰여 있으며, 플래그는 정확히 그 둘이 같지 않은 경우다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;순간&lt;/th&gt;
&lt;th&gt;사실인 것&lt;/th&gt;
&lt;th&gt;요청자에게 이미 알려야 하는가&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;코드 머지됨, 플래그는 어디서든 꺼짐&lt;/td&gt;
&lt;td&gt;기능은 존재하지만 아무도 쓸 수 없다&lt;/td&gt;
&lt;td&gt;아니다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;요청자의 계정에 플래그가 켜짐&lt;/td&gt;
&lt;td&gt;기능이 존재하고 그 특정 사람이 쓸 수 있다&lt;/td&gt;
&lt;td&gt;그렇다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;그 사람을 제외하는 출시 비율에 플래그가 켜짐&lt;/td&gt;
&lt;td&gt;기능이 존재하지만 그 사람은 여전히 쓸 수 없다&lt;/td&gt;
&lt;td&gt;아니다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;플래그가 완전히 제거되고 기능이 그냥 켜져 있음&lt;/td&gt;
&lt;td&gt;기능이 모두에게 존재한다&lt;/td&gt;
&lt;td&gt;아직 알리지 않았다면 그렇다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;누군가에게 언제 알려야 하는지에 대한 진짜 규칙은 무엇인가&lt;/h2&gt;
&lt;p&gt;플래그가 그들의 계정에 켜졌을 때 알려라, 코드가 머지되었을 때도 플래그가 만들어졌을 때도 아니다. 이 하나의 규칙이 위 표의 모든 줄을 다루는데, 요청자에게 정말로 중요한 유일한 사실, 즉 지금 당장 가서 그것을 쓸 수 있는가에 알림을 묶어두기 때문이다. 머지나 플래그 생성에 묶인 알림은 사실상 엔지니어링 진행 보고서이며, 기능을 요청한 사람은 진행 보고서를 원하는 게 아니라 언제 확인하러 가면 되는지 알고 싶어 한다.&lt;/p&gt;
&lt;h2&gt;그것은 요청자가 조기 접근이나 특별한 접근이 필요하다는 뜻인가&lt;/h2&gt;
&lt;p&gt;꼭 그런 것은 아니며, 그것을 강제하는 것은 그 자체로 문제를 만든다. 부하나 안정성 때문에 플래그가 점진적으로 출시되고 있다면, 단지 루프를 더 빨리 닫기 위해 한 계정을 대기열 맨 앞으로 옮기는 것은 애초에 출시가 단계적인 이유를 훼손한다. 정직한 선택지는 이렇다. 요청자의 계정이 자연스럽게 출시에 도달할 때까지 기다렸다가 그때 알리거나, 긴급성이 그것을 정당화한다면 알림을 보내고 싶은 마음의 부작용이 아니라 출시를 소유한 누군가의 진짜 결정으로서 의도적으로 그들에게 플래그를 먼저 켜주는 것이다.&lt;/p&gt;
&lt;h2&gt;플래그가 출시 메커니즘이 아니라 긴급 차단 스위치라면 어떤가&lt;/h2&gt;
&lt;p&gt;그러면 안전한 가정이 뒤집힌다. 릴리스를 단계화하기 위해서가 아니라 기능을 빠르게 끌 수 있도록 만들어진 플래그는 보통 그 기능이 생성되는 순간 완전히 라이브가 되도록 의도되었다는 뜻이며, 플래그는 순서를 위해서가 아니라 안전을 위해 존재한다. 그 경우 배포 시점에 요청자에게 알리는 것이 옳으며, 플래그 없는 다른 어떤 릴리스와도 같다. 플래그의 존재는 루프가 언제 닫히는지를 바꾸어서는 안 되는 운영상의 세부 사항이다. 중요한 구분은 플래그가 무엇을 위한 것인가이지, 하나가 존재하는가가 아니다.&lt;/p&gt;
&lt;h2&gt;플래그는 피처 플래그 릴리스 노트가 말해야 할 내용을 바꾸는가&lt;/h2&gt;
&lt;p&gt;그것은 항목이 언제 게시되는지를 바꾸지, 무엇을 담는지를 바꾸지 않는다. 플래그가 계정의 100%에 대해 켜진 바로 그 순간에 게시된 항목은 정확히 평범한 체인지로그 항목처럼 읽히며, 그래야 맞다. 나중에 그것을 찾는 독자는 플래그가 한때 관여했다는 사실을 알 이유가 전혀 없다. 하지 말아야 할 것은 플래그가 작은 출시 비율에만 켜져 있는 동안 게시하는 것인데, 공개 체인지로그 항목은 플래그 없는 계정을 포함해 그것을 읽는 모두를 찾을 수 없는 기능을 찾아 헤매게 만들기 때문이다. 이것은 같은 문제의 더 나쁜 버전이며, 한 요청자 규모가 아니라 제품 전체 규모로 일어난다. 이 타이밍 규칙이야말로 피처 플래그 릴리스 노트와 평범한 항목 사이의 유일한 차이다. 내용은 같고, 게시일만 움직인다. &lt;a href=&quot;https://changeloop.dev/blog/ko/how-to-write-release-notes/&quot;&gt;릴리스 노트 작성법&lt;/a&gt;은 여기에도 적용되는 &amp;quot;조치 필요 없음&amp;quot; 원칙을 다룬다. 독자는 이것이 자신에게 해당하는지 알아야지, 그것이 어딘가에 존재한다는 것만으로는 부족하다.&lt;/p&gt;
&lt;h2&gt;제품 업데이트 이메일은 플래그가 걸린 기능을 다르게 다뤄야 하는가&lt;/h2&gt;
&lt;p&gt;그렇다, 주로 다시 쓰는 대신 미루는 방식으로. &lt;a href=&quot;https://changeloop.dev/blog/ko/product-update-email/&quot;&gt;제품 업데이트 이메일 템플릿&lt;/a&gt;은 표적화된 알림과 넓은 다이제스트를 다룬다. 플래그가 걸린 기능은 표적화된 알림의 타이밍을 보내기 전에 수신자 자신의 플래그 상태와 맞춰봐야 하는 경우이며, 넓은 다이제스트는 그것을 전혀 쉽게 할 수 없다. 이것은 아직 출시 중간에 있는 모든 것에 다이제스트가 잘못된 채널인 또 다른 이유이기도 하다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;플래그는 존재하지만 아직 그 사람에게 켜지지 않았을 때 요청자에게 기능이 &amp;quot;곧 나온다&amp;quot;고 말해야 하는가?&lt;/strong&gt;
진짜로 가까운 날짜가 붙어 있을 때만, 그리고 그때도 아껴서 해야 한다. 날짜 없는 &amp;quot;곧&amp;quot;은 충분한 시간이 지나면 침묵과 똑같이 읽히며, 마찬가지로 추적하고 지켜야 할 두 번째 약속을 만든다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;플래그가 루프를 닫을 만큼 충분히 진행되었는지는 누가 결정하는가?&lt;/strong&gt;
알림을 소유한 사람이 아니라 출시를 소유한 누구든지다. 출시를 가진 사람은 &amp;quot;계정의 100%&amp;quot;가 임박했는지 아니면 아직 몇 주 남았는지 안다. 루프를 닫는 단계를 고정된 달력 날짜가 아니라 그들의 상태에 묶어두는 것이 알림을 정직하게 유지한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;영구적인 플래그(결코 완전히 제거되지 않는) 뒤의 기능도 언젠가 공개 체인지로그 항목을 받는가?&lt;/strong&gt;
그렇다, 그 제품에서 &amp;quot;일반 공개&amp;quot;가 의미하는 것에 도달하는 순간이다, 설령 플래그 자체가 운영상의 이유로 영원히 코드에 남아 있더라도. 체인지로그 항목은 독자에게 있어서의 가용성에 관한 것이지, 그 가용성이 어떻게 구현되는지에 관한 세부 사항이 아니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;플래그가 제거되고 기능이 출시 대신 폐기되면 어떻게 되는가?&lt;/strong&gt;
그것은 거절이지, 출시 알림이 아니며, 다른 어떤 거절과도 같은 정성을 받을 자격이 있다. &lt;a href=&quot;https://changeloop.dev/blog/ko/declining-feature-requests/&quot;&gt;기능 요청을 거절하는 방법&lt;/a&gt;은 그 메시지가 무엇을 말해야 하는지를 다룬다. 정직하게 루프를 닫는다는 것은 때때로 그것을 거절로 닫는다는 뜻이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;피처 플래그 릴리스 노트는 평범한 항목과 별도의 템플릿이 필요한가?&lt;/strong&gt;
템플릿은 바뀌지 않으며, 게시 전에 게이팅 단계만 하나 추가된다. 코드가 머지되었다는 것만이 아니라 요청한 계정의 플래그 상태를 확인하고, 그 확인이 통과할 때까지 항목을 보류하라. 항목에 관한 나머지, 즉 문구, 길이, FAQ 원칙은 다른 어떤 릴리스 노트와도 같다.&lt;/p&gt;
</content:encoded></item><item><title>지원 티켓 대 기능 요청: 무엇을 신뢰해야 하는가</title><link>https://changeloop.dev/blog/ko/feedback-signal-quality/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/feedback-signal-quality/</guid><description>지원 티켓과 기능 요청 게시판은 서로 다른 것을 측정한다. 한쪽의 급증을 다른 쪽의 급증과 똑같이 취급하면 자신만만하지만 잘못된 우선순위가 나온다.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;기능 요청 게시판은 사용자가 앉아서 무엇을 원하는지 설명할 시간이 있을 때 요청하는 것을
포착한다. 지원 티켓은 사용자가 바로 지금 막혀 있는 것을 포착하는데, 흔히 짜증이 난 상태로,
흔히 근본적인 요청을 깔끔하게 설명할 어휘도 없이. 둘 다 진짜 신호이며, 둘 중 하나만 보는
팀은 결국 자신만만하게 잘못된 문제를 해결하게 되는데, 각 채널이 체계적으로 서로 다른 유형의
사용자와 서로 다른 유형의 필요를 과대 대표하기 때문이다. &lt;a href=&quot;https://changeloop.dev/blog/ko/prioritizing-feature-requests/&quot;&gt;기능 요청 우선순위
매기기&lt;/a&gt;는 이미 게시판에 있는 것의 순위를 매기는 것을
다룬다. 이 글은 애초에 게시판에 도달하는 것과 지원 티켓으로만 나타나는 것 사이의 격차에
관한 것이다.&lt;/p&gt;
&lt;h2&gt;왜 같은 근본적인 문제가 한 채널에는 나타나고 다른 채널에는 나타나지 않는가&lt;/h2&gt;
&lt;p&gt;두 채널이 서로 다른 활성화 비용을 가지고 있고, 그 비용의 크기가 누가 그것을 넘어서는지를
결정하기 때문이다. 기능 요청을 제출하는 것은 주도성을 요구한다. 사용자는 그 요청을 명확히
표현할 가치가 있다고 믿고, 게시판을 찾고, 일관된 무언가를 써야 하는데, 이는 이미 제품에
투자한 참여적이고 인내심 있는 사용자를 선별한다. 지원 티켓을 제출하는 것은 그에 비해 거의
주도성을 요구하지 않으며, 흔히 작업 도중에 그냥 &amp;quot;도움&amp;quot;을 클릭하는 것뿐인데, 이는 게시판을
전혀 사용하지 않았을 사용자를 포함해 그 순간 좌절한 사용자를 포착한다는 의미다. 제품의
진짜 격차는, 그것을 마주치는 사용자가 공식 요청을 제출할 가능성이 가장 낮은 사람들이라는
이유만으로 기능 게시판에서는 보이지 않고 지원팀에서는 시끄러울 수 있다.&lt;/p&gt;
&lt;h2&gt;누락된 기능에 대한 티켓 양은 그것에 대한 투표 수와 같은 것을 의미하는가&lt;/h2&gt;
&lt;p&gt;아니다, 서로 다른 조건에서 서로 다른 모집단을 측정하기 때문이다. 백 표를 받은 기능 요청은
기존 요청을 찾아 지지하는 데 시간을 들인 백 명을 대표하며, 이는 지속적이고 신중한 수요의
강한 신호다. 같은 기간에 제출된, 같은 근본적인 격차에 관한 백 개의 지원 티켓은 아마도 그
순간 벽에 부딪힌 사용자를 대표하며, 그중 일부는 즉각적인 마찰이 지나가면 완전히 잊어버릴
것이다. 둘 다 &amp;quot;백 명이 이것을 원한다&amp;quot;는 동등한 신호로 취급하는 것은 티켓 양을 과대평가하는데,
티켓은 생성하기 저렴하고 투표는 그렇지 않기 때문이다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;기능 요청 게시판&lt;/th&gt;
&lt;th&gt;지원 티켓&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;제출에 주도성이 필요함&lt;/td&gt;
&lt;td&gt;거의 필요하지 않음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;신중하고 지속적인 수요를 포착함&lt;/td&gt;
&lt;td&gt;그 순간의 좌절을 포착함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;참여적이고 인내심 있는 사용자로 기울어짐&lt;/td&gt;
&lt;td&gt;게시판을 결코 사용하지 않을 사용자를 포착함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;투표 수는 진짜 헌신 신호임&lt;/td&gt;
&lt;td&gt;티켓 수는 마찰을 반영하며, 항상 욕구는 아님&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;기능에 지원 티켓은 있지만 게시판에는 투표가 거의 없을 때 무엇을 의미하는가&lt;/h2&gt;
&lt;p&gt;흔히, 요청은 존재하지만 그것을 마주치는 사용자가 게시판이 존재한다는 것을 모르거나, 투표가
무언가를 바꿀 것이라고 믿지 않거나, 문제를 너무 드물게 마주쳐서 공식적으로 등록하기 위해
채널을 바꾸는 수고를 하지 않는다는 것이다. 이것은 정확히 기능 요청 게시판이 구조적으로
놓치는 모집단이며, 여기서 낮은 투표 수는 낮은 수요의 증거가 아니라 측정 격차의 증거다.
해결책은 티켓을 불신하는 것이 아니라, 누락된 기능을 둘러싼 지원 티켓 클러스터를 투표 수만
가지고 우선순위를 매기는 사람에게 보이지 않게 남지 않도록 여러분 스스로 사용자를 대신해
게시판에 기록하는 자체 신호로 취급하는 것이다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;게시판은 낮은 우선순위로 읽힘:
&amp;quot;Export to CSV&amp;quot;: 6개월간 4표

지원팀은 다른 이야기를 전함:
&amp;quot;Export to CSV&amp;quot;: 같은 기간 31건의 티켓, 각각 다른
계정에서, 각각 &amp;quot;현재 지원되지 않음, 피드백을
전달하겠음&amp;quot;으로 종료됨
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;지원 티켓의 급증은 항상 근본적인 문제가 누락된 기능이라는 것을 의미하는가&lt;/h2&gt;
&lt;p&gt;아니다, 그리고 여기서 두 채널은 반대 방향으로 오도할 수 있다. 티켓 급증은 이미 존재하는
기능을 둘러싼 혼란스러운 인터페이스, 버그, 또는 충분한 설명 없이 나온 변경으로 인해 그만큼
자주 발생하는데, 그중 어느 것도 새로운 것을 만드는 것으로 해결되지 않는다. 모든 티켓 급증을
&amp;quot;사용자가 우리에게 없는 기능을 원한다&amp;quot;로 읽는 것은 실제로는 문서 격차이거나 위장된 사용성
문제였던 것들로 가득한 로드맵을 만들어낸다. 지원 티켓은 마찰이 어디에 있는지 알려준다. 그것
자체로는 해결책이 새 기능인지, 인터페이스 변경인지, 더 나은 도움말 문서인지 알려주지 않으며,
그것을 혼동하는 것은 잘못된 해결책에 엔지니어링 시간을 낭비하게 한다.&lt;/p&gt;
&lt;h2&gt;무엇을 만들지 결정할 때 두 신호는 실제로 어떻게 결합되어야 하는가&lt;/h2&gt;
&lt;p&gt;티켓을 사용해 마찰이 어디에 있는지 찾고, 게시판이 부실한 곳에서는 직접적인 접촉과 함께 기능
요청 게시판을 사용해 실제로 원하는 결과가 어떤 모습인지 확인하라. 티켓 클러스터는 진짜의,
느껴지는 문제를 식별한다. 그것에 맞서 무언가를 만들 수 있을 만큼 정확하게 해결책을 명시하는
경우는 드문데, 지원팀과의 대화에서 좌절한 사용자는 사양이 아니라 증상을 설명하기 때문이다.
기능 요청 게시판은, 같은 근본적인 문제에 충분한 투표가 있을 때, &amp;quot;실제로 무엇이 이것을
만족시킬지&amp;quot;에 대한 세부 사항을 더 많이 담는 경향이 있는데, 요청을 쓰는 것 자체가 무엇이
잘못됐는지 보고하는 것이 아니라 원하는 것을 명시하는 행위이기 때문이다.&lt;/p&gt;
&lt;h2&gt;지원 상담원은 스스로 티켓을 기능 요청으로 기록해야 하는가&lt;/h2&gt;
&lt;p&gt;그렇다, 그리고 이것이 두 채널 사이의 격차에 대한 가장 레버리지가 큰 단일 수정이다. 티켓을
위장된 기능 요청으로 인식하는 상담원은, 그것을 그냥 해결하고 넘어가는 대신, 고객을 대신해
게시판에 기록할 수 있는데, 이는 고객이 스스로 두 번째 채널을 발견하고 사용하도록 요구하는
대신 측정 격차를 직접 메운다. 이것은 기록하는 것이 상담원에게 몇 분이 아니라 몇 초 걸릴 때만
작동하며, 그래야 그렇게 하는 마찰이 그냥 티켓을 닫고 다음으로 넘어가는 마찰보다 낮아진다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;기능 요청 투표는 모두 하나의 계정이나 팀에서 온 경우 할인되어야 하는가?&lt;/strong&gt;
그렇다, 순수 투표 수 대신 별개의 계정이나 조직으로 가중치를 매겨라. 같은 회사의 다섯 명에게서
나온 다섯 표는 다섯 개의 독립적인 수요 확인이 아니라 한 고객의 우선순위를 대표하기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;티켓에는 많이 나타나지만 투표는 거의 없는 기능을 만들 가치가 있는가?&lt;/strong&gt;
흔히 그렇다, 티켓 양이 진짜로 별개의 계정에서 나오고 근본적인 필요가 가정이 아니라 확인된
경우라면. 낮은 투표 수를 수요가 진짜가 아니라는 증거가 아니라 게시판의 활성화 비용에 대한
측정 부산물로 취급하라.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UI 혼란 티켓과 진짜 누락 기능 티켓을 한눈에 어떻게 구별하는가?&lt;/strong&gt;
해결책이 기존 기능을 설명하는 것인지 아니면 누락된 것에 대해 사과하는 것인지를 보라. &amp;quot;아,
사실 바로 거기 있네요&amp;quot; 해결의 패턴은 인터페이스나 발견 가능성 문제를 가리키고, &amp;quot;그건 아직
지원하지 않습니다&amp;quot; 패턴은 진짜 격차를 가리킨다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;이 구별은 아주 작은 지원 규모에서도 똑같이 중요한가?&lt;/strong&gt;
기계적으로는 덜 중요한데, 소수의 티켓은 집계 분석 없이도 개별적으로 읽기 쉽기 때문이다. 하지만
티켓이 좌절한 사용자를 과대 대표하고 인내심 있는 사용자를 과소 대표한다는 근본적인 편향은
어떤 규모에서든 존재하며, 여러분이 직접 모든 티켓을 읽을 때조차 명심할 가치가 있다.&lt;/p&gt;
</content:encoded></item><item><title>Git 태그, 릴리스, 그리고 당신의 체인지로그</title><link>https://changeloop.dev/blog/ko/git-tags-releases-changelog/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/git-tags-releases-changelog/</guid><description>Git 태그, 릴리스, 체인지로그 항목은 하나의 사건에 대한 세 가지 기록이다. 이를 혼동하면 체인지로그가 실제 릴리스에서 벗어난다. 맞추는 법을 설명한다.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Git 태그, 릴리스, 체인지로그 항목은 같은 사건에 대한 세 가지 다른 기록이며, 이것들을 혼동하면 체인지로그가 실제로 출시된 것에서 조용히 멀어지게 된다. 태그는 커밋을 표시한다. 릴리스는 그 태그를 아티팩트와 설명으로 패키징한다. 체인지로그 항목은 저장소 밖의 독자가 사용할 수 있는 용어로 무엇이 바뀌었는지 설명한다. 보통 시간적으로 가깝게 일어나며, 바로 그렇기 때문에 셋을 하나의 단계로 취급하기 쉽고, 바로 그렇기 때문에 그 격차는 누군가 &amp;quot;v2.4에 뭐가 출시됐지&amp;quot;라고 묻고 정직한 답이 진짜 발굴을 필요로 할 때에야 몇 달 후에 비로소 눈에 보이게 된다.&lt;/p&gt;
&lt;h2&gt;셋 사이의 실제 차이는 무엇인가&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;기록&lt;/th&gt;
&lt;th&gt;존재하는 곳&lt;/th&gt;
&lt;th&gt;대상&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Git 태그&lt;/td&gt;
&lt;td&gt;저장소, 참조로서&lt;/td&gt;
&lt;td&gt;정확히 그 커밋을 체크아웃하는 모든 사람&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;릴리스&lt;/td&gt;
&lt;td&gt;코드 호스트(GitHub, GitLab)&lt;/td&gt;
&lt;td&gt;빌드를 다운로드하는 모든 사람&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;체인지로그 항목&lt;/td&gt;
&lt;td&gt;제품 자체의 체인지로그&lt;/td&gt;
&lt;td&gt;저장소만이 아니라 제품을 사용하는 모든 사람&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;태그는 셋 중 가장 기계적이다. &lt;code&gt;git tag v2.4.0&lt;/code&gt; 하면 끝이고, 무언가가 그 안에 무엇이 있는지 설명해야 한다는 요구사항이 전혀 없다. 릴리스는 설명과 보통 다운로드 가능한 아티팩트를 추가하며, 그 대상은 여전히 릴리스 페이지가 무엇인지 아는 개발자들이다. 체인지로그 항목은 셋 중 유일하게 저장소를 절대 열지 않을 수도 있는 독자를 위해 작성되며, 그래서 가장 많은 편집상의 주의가 필요하고 마감 압박 속에서 가장 건너뛰기 쉬운 것이다.&lt;/p&gt;
&lt;h2&gt;모든 git 태그에 체인지로그 항목이 필요한가&lt;/h2&gt;
&lt;p&gt;아니다, 그리고 둘을 1대1로 취급하는 것은 흔한 실수다. 태그는 내부 마일스톤, 릴리스 후보, 또는 대부분의 사용자에게 절대 도달하지 않는 핫픽스를 표시할 수 있다. 이 중 어느 것도 반드시 공개 항목이 필요한 것은 아니다. 테스트는 애초에 무언가가 체인지로그에 속하는지 결정하는 것과 같다. 사용자나 호출자가 그것을 알아차리거나 신경 쓸 것인가. 대부분의 태그는 이 테스트를 통과한다. CI 파이프라인을 트리거하기 위해서만 만들어진 태그처럼 일부는 절대 통과하지 못한다.&lt;/p&gt;
&lt;h2&gt;모든 체인지로그 항목에 자체 태그가 필요한가&lt;/h2&gt;
&lt;p&gt;항상 그런 것은 아니며, 여기서 지속적으로 배포하는 팀과 버전이 매겨진 패키지를 출시하는 팀이 갈린다. 하루에 여러 번 배포하는 SaaS 제품은 배포당 1대1 태그 없이 여러 배포를 하나의 날짜가 적힌 체인지로그 항목 아래 묶을 수 있다. 패키지 레지스트리에 게시되는 라이브러리는 보통 게시된 버전마다 태그가 필요하다. Go 모듈과 Swift Package Manager는 태그 자체로부터 버전을 해석한다. npm이나 PyPI에서는 레지스트리가 게시된 버전을 보관하며, 태그는 누구든 그 버전을 소스와 다시 연결하는 수단이다. 독립적으로 버전이 매겨지는 여러 패키지를 가진 저장소는 이것을 저장소 전체를 위해 한 번이 아니라 패키지 단위로 결정해야 하며, &lt;a href=&quot;https://changeloop.dev/blog/ko/monorepo-changelogs/&quot;&gt;모노레포 체인지로그&lt;/a&gt;가 태그 접두사와 체인지로그 범위가 폴더 경계가 아니라 패키지 경계를 따라야 하는 이유를 다룬다. &lt;a href=&quot;https://changeloop.dev/blog/ko/semantic-versioning-changelog/&quot;&gt;시맨틱 버저닝과 당신의 체인지로그&lt;/a&gt;가 버전 번호 자체가 체인지로그 카테고리에 어떻게 매핑되어야 하는지를 다룬다. 태그는 버전 번호를 실제 코드에 대해 검증 가능하게 만드는 메커니즘이다.&lt;/p&gt;
&lt;h2&gt;릴리스 설명은 체인지로그 항목과 어떻게 관련되어야 하는가&lt;/h2&gt;
&lt;p&gt;같은 텍스트일 수 있지만, 그것은 오직 둘의 대상이 진짜로 같을 때뿐이며, 이는 보이는 것보다 드물다. 코드 호스트의 릴리스 페이지는 거의 전적으로 개발자만 읽는다. 제품에 체인지로그를 읽는 비기술직 사용자도 있다면, 릴리스 설명을 그대로 복제하는 것은 평이한 언어 버전이 필요했던 독자에게 내부 용어와 코드 중심 표현을 보내는 것이다. 가장 깔끔한 패턴은 체인지로그 항목을 주요한, 독자 지향적인 아티팩트로 작성하고, 릴리스 설명은 거기로 링크하거나 이미 그곳에 익숙한 대상을 위해 더 짧고 더 기술적인 요약을 유지하도록 두는 것이다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 릴리스 v2.4.0 (GitHub, 개발자용)
보고서 파이프라인을 새 집계 엔진으로 업그레이드. 고객 지향 요약은
체인지로그 참조: https://example.com/changelog#v2.4.0

## 2026-09-07 (체인지로그, 고객 지향)
### Added
- 이제 보고서가 백만 행이 넘는 계정에서도 1초 이내에 로드된다.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;같은 릴리스, 두 개의 문서, 각각 자신의 독자를 위한 자신의 표현으로.&lt;/p&gt;
&lt;h2&gt;체인지로그 항목은 실제로 어디서 오는가&lt;/h2&gt;
&lt;p&gt;두 가지 출발점에서, 그리고 대부분의 실제 파이프라인은 둘의 혼합이다. 태그 시점에 커밋 메시지에서 생성될 수 있으며, 이는 빠르고 병합된 풀 리퀘스트를 절대 놓치지 않는다. &lt;a href=&quot;https://changeloop.dev/blog/ko/conventional-commits-changelog/&quot;&gt;Conventional Commits에서 체인지로그로&lt;/a&gt;가 그 파이프라인을 완전히 다룬다. 또는 태그와 완전히 별개로 손으로 작성될 수 있으며, 코드가 병합되는 순간이 아니라 기능이 완료되었다고 간주되는 순간에 맞춰진다. 생성된 항목은 일관되지만 모호한 커밋 메시지를 그대로 물려받는다. 손으로 작성된 항목은 더 명확하지만 실제로 그것을 쓸 누군가가 필요하다. 자동화하는 대부분의 팀도 원본 결과물을 그대로 보여주는 대신, 그것이 공개 항목이 되기 전에 생성된 텍스트에 가벼운 편집 단계를 유지한다. &lt;a href=&quot;https://changeloop.dev/blog/ko/keep-a-changelog-implemented/&quot;&gt;Keep a Changelog, 실전편&lt;/a&gt;이 권장하는 것과 같은 원칙이며, 원본 텍스트가 애초에 어디서 왔는지와 상관없이 그렇다.&lt;/p&gt;
&lt;h2&gt;셋이 동기화에서 벗어나면 무엇이 깨지는가&lt;/h2&gt;
&lt;p&gt;독자가 먼저 확인한 것에 대한 신뢰다. 대응하는 체인지로그 항목 없이 존재하는 태그는 체인지로그 독자 쪽에서 보면 그 주에 아무 일도 없었던 것처럼 보인다. 대응하는 태그나 릴리스가 없는 체인지로그 항목은 프로덕션 문제를 디버깅하는 누군가가 항목이 게시되었을 때 라이브였던 정확한 코드를 체크아웃하는 것을 불가능하게 만든다. 해법은 완벽한 자동화가 아니라 그 대응 관계에 대한 단일한 진실의 원천이다. 릴리스 프로세스 자체의 체크리스트일 뿐이라도, 출시 가능한 변경이 그것을 도입하는 같은 커밋이나 풀 리퀘스트에서 셋 모두를 받는다고 말하는 한 장소.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;체인지로그 항목은 git 태그에서 자동으로 생성되어야 하는가?&lt;/strong&gt;
출발점이 될 수는 있지만, 태그 하나만으로는 독자 지향적인 설명을 전혀 담지 못한다, 커밋 범위만 담을 뿐이다. 자동화된 생성은 사용 가능한 무언가를 만들어내려면 태그의 존재뿐만 아니라 그 범위 안의 커밋 메시지를 읽어야 한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;모든 릴리스에 태그를 달지 않으면 어떻게 되는가?&lt;/strong&gt;
그러면 체인지로그 항목이 주요 기록이 되며, 그래도 날짜와, 제품에 버전이 있다면 버전 번호를 담아야 한다, 대응하는 태그가 없어도 항목이 나중에 독자가 참조할 수 있는 것으로 남도록.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;사전 릴리스 태그(&lt;code&gt;v2.4.0-rc.1&lt;/code&gt; 같은)도 체인지로그 항목을 가져야 하는가?&lt;/strong&gt;
일반적으로는 아니다. 릴리스 후보는 내부 또는 베타 테스트용이며, 그것을 위한 체인지로그 항목은 독자에게 설명된 그대로 절대 출시되지 않을 수도 있는 버전에 대한 항목을 기대하도록 훈련시킨다. 항목은 일반 공급에 도달하는 태그를 위해 남겨두라.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;하나의 체인지로그 항목이 여러 git 태그를 다룰 수 있는가?&lt;/strong&gt;
그렇다, 그리고 자주 태그를 다는 팀에게는 종종 그래야 한다. 기능을 여러 읽기에 걸쳐 조각내는 태그당 얇은 항목을 게시하는 대신, 관련된 태그를 순 변경 사항을 설명하는 하나의 날짜가 적힌 항목 아래로 묶으라.&lt;/p&gt;
</content:encoded></item><item><title>내부용 API 체인지로그: 다른 팀에게 무엇이 달라지는가</title><link>https://changeloop.dev/blog/ko/internal-api-changelog/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/internal-api-changelog/</guid><description>공개 API 체인지로그에는 직접 연락할 수 없는 독자가 있고, 내부용에는 두 층 떨어진 독자가 있다. 이 차이가 체인지로그의 책임을 어떻게 바꾸는지 짚어본다.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;이 허브의 다른 모든 글은 API를 호출하는 쪽이 회사 밖에 있다고 가정한다. 고객사의 엔지니어, 파트너사, 문서를 스스로 찾아낸 누군가. 하지만 많은 API에는 완전히 다른 종류의 호출자가 있다. 복도 건너편이나 두 층 떨어진 곳에 있는 팀이다. 그리고 이것은 체인지로그가 그들에게 무엇을 빚지고 있는지에 대한 계산을 바꾸는데, 슬랙 메시지 하나면 그들에게 닿기 때문이고 서포트 티켓은 보통 아예 열리지 않기 때문이다. 대부분의 팀은 여기서 내부용 API는 체인지로그가 필요 없다는 결론을 내린다. 실제로 필요한 것은 다른 종류의 체인지로그다.&lt;/p&gt;
&lt;h2&gt;내부용 API의 체인지로그를 공개용과 다르게 만드는 것은 무엇인가&lt;/h2&gt;
&lt;p&gt;독자에게 직접 다가갈 수 있다는 점이며, 이것은 대부분의 공개 API 체인지로그가 존재하는 주된 이유, 즉 개별적으로 연락할 수 없는 호출자들에게 방송하는 이유를 없애버린다. 내부용 API를 소유한 팀은 보통 어떤 다른 팀이 그것을 호출하는지, 때로는 구체적인 서비스 단위까지 정확히 알고 있다. 이것은 공개 피드가 아니라 표적화된 메시지를 자연스러운 기본값으로 만들고, 그래서 내부용 API가 그토록 자주 체인지로그 없이 끝나는 이유이기도 하다. 소유 팀은 기억하고 있는 두세 팀에게만 알리고, 그것으로 모두를 다뤘다고 가정한다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;공개 API 체인지로그&lt;/th&gt;
&lt;th&gt;내부용 API 체인지로그&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;누가 읽는가&lt;/td&gt;
&lt;td&gt;직접 닿기 어려운 임의의 외부 호출자&lt;/td&gt;
&lt;td&gt;보통 알려져 있는 소규모 내부 팀 집합&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;기본 채널&lt;/td&gt;
&lt;td&gt;페이지와 피드&lt;/td&gt;
&lt;td&gt;호출하는 팀들에게 보내는 메시지, 이상적으로는 페이지도&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;가장 큰 위험&lt;/td&gt;
&lt;td&gt;호출자가 항목을 완전히 놓친다&lt;/td&gt;
&lt;td&gt;소유 팀이 존재하는지도 모르는 호출자를 잊는다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;quot;누가 우리를 호출하는지 모른다&amp;quot;를 대체하는 것&lt;/td&gt;
&lt;td&gt;아무것도 없다; 널리 게시할 뿐&lt;/td&gt;
&lt;td&gt;최신 상태로 유지되는 실제 호출자 레지스트리&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;왜 &amp;quot;우리를 호출하는 팀들에게만 알리면 된다&amp;quot;는 무너지는가&lt;/h2&gt;
&lt;p&gt;호출자 집합이 소유 팀이 기억하는 것만큼 작거나 정적인 적이 없기 때문이다. 한 소비자를 위해 만들어진 서비스는 여섯 달 뒤, 아무도 발표하지 않은 통합을 통해 두 번째 호출자를 얻고, 소유 팀 머릿속의 &amp;quot;누가 우리를 호출하는가&amp;quot; 목록은 이제 틀렸는데도 아무도 그것을 알아채지 못한다. 이 실패는 흔하고 평범하다. 기록 대신 기억에 의존한 결과일 뿐, 누군가 부주의했다는 신호가 아니다. &lt;a href=&quot;https://changeloop.dev/blog/ko/breaking-changes/&quot;&gt;브레이킹 체인지란 무엇인가&lt;/a&gt;는 애초에 API 변경이 브레이킹으로 간주되는지 어떻게 결정하는지를 다룬다. 내부용의 경우는 그 위에 누구에게 알려야 하는지 아는 것이라는 더 어려운 두 번째 질문을 얹는다.&lt;/p&gt;
&lt;h2&gt;내부용 API도 공개용 스타일의 체인지로그 페이지가 필요한가&lt;/h2&gt;
&lt;p&gt;주요 채널이 직접적이라 해도 보통은 필요하다. 페이지가 있으면 직접 보내는 메시지가 참조할 대상이 생기므로, 알림을 짧게 유지할 수 있다(&amp;quot;&lt;code&gt;/v2/accounts&lt;/code&gt;에 브레이킹 체인지, 자세한 내용은 여기&amp;quot;) 스크롤되어 사라질 채팅 메시지에 전체 설명을 담으려 애쓰는 대신 말이다. 그것은 또한 새로운 팀이나 직접 메시지를 놓친 팀이, 통합이 깨졌을 때 왜 그런지 알아내려 할 때 확인할 수 있는 곳이 된다. 페이지가 세련되거나 공개될 필요는 없다. 링크할 수 있어야 하고 그것을 알린 슬랙 스레드보다 오래 살아남아야 할 뿐이다.&lt;/p&gt;
&lt;h2&gt;실제로 호출자 목록을 관리하는 것은 누구인가&lt;/h2&gt;
&lt;p&gt;소유 팀이며, 이것은 구전 지식이 아니라 실제 산출물로 다뤄져야 한다. 가장 저렴한 버전은 API 자체 저장소 안의 파일로, 새 통합이 만들어질 때마다 갱신되는 소비 서비스들의 짧은 목록에 항목마다 담당자를 붙인 것이다. 이것은 어떤 의존성 선언과도 같은 규율이다. 매번 브레이킹 체인지 전에 여기저기 물어보는 대안은 누군가가 올바른 사람에게 묻는 것을 잊는 그 한 번의 순간까지는 작동한다. 한 팀을 위해 조용히 깨지는 내부용 API는 공개용보다는 작은 사고지만, 여전히 사고이며, 보통은 API 소유자가 아니라 그 팀 자체의 온콜이 발견한다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# consumers.yml
- service: billing-service
  owner: &amp;quot;#team-billing&amp;quot;
  since: 2026-03-01
- service: reporting-pipeline
  owner: &amp;quot;#team-analytics&amp;quot;
  since: 2026-06-14
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이런 파일은 &amp;quot;누구에게 알려야 하는가&amp;quot;를 질문에서 조회로 바꾼다. 바로 이 문제를 위해 만들어진
도구들, 예를 들어 &lt;a href=&quot;https://backstage.io/docs/features/software-catalog/system-model/&quot;&gt;Backstage의 서비스
카탈로그&lt;/a&gt;는 같은 이유로
API를 선언된 소비자를 가진 일급 엔터티로 모델링한다. 조직이 내부 서비스를 충분히 많이
갖게 되면 누가 무엇을 호출하는지에 대한 기억은 저절로 정확하게 유지되지 않으며, 대신 그
기록을 보관할 무언가가 있어야 한다. 이미 사내에서 쓰고 있는 도구의 &lt;a href=&quot;https://changeloop.dev/docs&quot;&gt;문서&lt;/a&gt;를 먼저
확인하는 것이 자체 제작에 나서기 전에 보통 옳은 순서다.&lt;/p&gt;
&lt;h2&gt;공개용에는 필요 없을 내부용 체인지로그 항목에 속하는 것은 무엇인가&lt;/h2&gt;
&lt;p&gt;더 많은 운영상의 구체성이다. 독자는 같은 인프라 안에서 이것을 근거로 행동할 또 다른 엔지니어이지, 이것을 요약으로 읽지 않기 때문이다. 변경이 어느 환경에서 언제 라이브되는지, 내부용 서비스는 공개 호출자가 결코 보지 못하는 단계들을 거쳐 승격되는 경우가 많기 때문이다. 변경이 소비 측에서 설정이나 클라이언트 라이브러리 업데이트를 요구하는지, 있다면 명령어로 표현된 형태로. 그리고 내부 호출자는 종종 소유 팀과 직접 수정을 조율할 수 있기 때문에, 서포트 채널 대신 이름이 명시된 담당자를 넣는다. &amp;quot;이게 뭔가 망가뜨리면 @maria에게 알려주세요&amp;quot;는 내부용 항목에서는 완전히 합리적인 한 줄이고 공개 API 체인지로그에서는 이상한 한 줄이다.&lt;/p&gt;
&lt;h2&gt;이것은 모노레포 안의 체인지로그에도 똑같이 적용되는가&lt;/h2&gt;
&lt;p&gt;이것은 문제를 대체하는 대신 같은 문제를 날카롭게 만든다. &lt;a href=&quot;https://changeloop.dev/blog/ko/monorepo-changelogs/&quot;&gt;모노레포 체인지로그&lt;/a&gt;는 패키지가 언제 자기만의 체인지로그가 필요한지 다룬다. 모노레포 안의 여러 패키지 중 하나인 내부용 API도 소비자가 명시적으로 추적되어야 한다는 점은 여전한데, 호출자와 같은 저장소를 공유한다고 해서 무언가가 보라고 알려주지 않는 한 그들이 변경을 알아챌 것이라는 뜻은 아니기 때문이다. 저장소 안에서의 가까움은 주의를 기울이는 것에서의 가까움과 같지 않다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;순수하게 내부용인 API가 호출자가 하나뿐이라면 체인지로그가 필요한가?&lt;/strong&gt;
거의 필요 없으며, 그 한 팀에게 보내는 직접 메시지로 보통 충분하다. 체인지로그는 호출자가 하나를 넘어서는 순간, 또는 호출자 목록이 소유 팀을 한 번이라도 놀라게 한 순간부터 제값을 한다. 그것이 기억만으로는 더 이상 믿을 수 없다는 신호이기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;내부용 API 변경도 공개용과 같은 리뷰를 거쳐야 하는가?&lt;/strong&gt;
독자가 외부 호출자가 아니라 동료이므로 표현은 더 가벼워도 되지만, 변경이 브레이킹인지 판단하는 것은 두 경우 모두 같은 주의를 받을 가치가 있다. 내부 호출자에게도 여전히 예전 동작에 의존하는 프로덕션 코드가 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;한 번도 추적된 적이 없다면 누가 내부용 API를 호출하는지 어떻게 알아내는가?&lt;/strong&gt;
소비자 레지스트리가 한 번도 유지되지 않았다면 서버 로그나 서비스 메시의 트래픽 데이터가 정직한 답이다. 그 발견을 일회성 정리가 아니라 레지스트리를 시작하는 순간으로 다뤄라.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;슬랙 메시지만으로 충분한가, 아니면 내부용 변경도 정식 체인지로그 항목이 필요한가?&lt;/strong&gt;
순전히 추가적인 것이 아닌 모든 것에 대해서는 둘 다 필요하다. 메시지는 제때 읽히는 것이고, 항목은 몇 주 뒤 문제를 조사하며 그 메시지를 본 적이 없는 팀이 그래도 찾아낼 수 있는 것이다.&lt;/p&gt;
</content:encoded></item><item><title>내부용 릴리스 노트: 그 밖에 누가 알아야 하는가</title><link>https://changeloop.dev/blog/ko/internal-release-notes/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/internal-release-notes/</guid><description>지원팀과 영업팀은 보통 당황한 고객에게서 출시 소식을 듣는다. 내부용 릴리스 노트는 이를 해결하며, 고객용 노트와는 다른 형태로 먼저 도착해야 한다.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;이 허브의 다른 모든 글은 릴리스 노트를 읽는 사람이 고객이라고 가정한다. 지원팀, 영업팀, 고객 성공팀도 읽으려 하지만, 대부분은 고객이 먼저 물어봐서 무엇이 출시됐는지 알게 된다. 이 순서는 뒤바뀌어 있고, 이것은 대부분의 회사에서도 기본값인데, 릴리스 프로세스가 고객용 노트가 나가는 순간 끝나버리고, 한 시간 뒤 그것에 대한 질문에 답해야 하는 사람들을 위한 두 번째의 더 작은 단계를 아무도 만들어두지 않았기 때문이다.&lt;/p&gt;
&lt;h2&gt;내부용 릴리스 노트란 무엇이며, 고객용 노트와 어떻게 다른가&lt;/h2&gt;
&lt;p&gt;이것은 제품을 이미 깊이 아는 사람들을 위해 쓰인 더 짧은 문서로, 무엇이 바뀌었고 그들의 구체적인 업무에서 그것에 대해 무엇을 해야 하는지를 알려준다. 지원팀 담당자는 고객용 발표가 쓰는 다듬어진 틀이 필요 없다. 그들에게 필요한 것은 그 변경이 지금 제품에서 어떻게 보이는지, 그것에 대해 가장 나올 법한 질문이 무엇인지, 그리고 열려 있는 티켓이 영향을 받는지다. 고객용 노트는 변경 사항을 판매한다. 내부용 노트는 누군가가 그것을 다룰 수 있도록 무장시킨다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;독자&lt;/th&gt;
&lt;th&gt;알아야 할 것&lt;/th&gt;
&lt;th&gt;어디서 필요한가&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;지원팀&lt;/td&gt;
&lt;td&gt;UI에서 무엇이 바뀌었는지, 나올 법한 질문, 영향받는 열린 티켓&lt;/td&gt;
&lt;td&gt;이미 답을 찾는 곳&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;영업팀&lt;/td&gt;
&lt;td&gt;어떤 거래를 열어주는지, 아직 하지 못하는 것&lt;/td&gt;
&lt;td&gt;통화를 준비하는 곳&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;고객 성공팀&lt;/td&gt;
&lt;td&gt;기존 고객에게 무엇을 말해야 하는지, 누가 요청했는지&lt;/td&gt;
&lt;td&gt;아웃리치를 계획하는 곳&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;경영진&lt;/td&gt;
&lt;td&gt;약속한 것에 비해 무엇이 출시됐는지, 언제&lt;/td&gt;
&lt;td&gt;릴리스마다가 아니라 짧고 반복되는 요약&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;내부 팀들은 왜 출시 소식을 늦게 알게 되는가&lt;/h2&gt;
&lt;p&gt;릴리스 프로세스가 보통 하나의 산출물, 즉 고객용 노트나 체인지로그 항목을 중심으로 짜여 있고, 내부적인 모든 것이 그 하나의 문서를 읽는 데서 나올 것이라고 가정되기 때문이다. 실제로는 그렇지 않다. 지원팀 담당자들은 눈앞의 티켓에 매여 있지, 맥락을 찾아 체인지로그를 뒤적이고 있지 않으며, 고객을 위해 쓰인 노트는 흔히 담당자에게 필요한 바로 그 운영상의 세부 사항, 이를테면 그 기능이 어느 요금제에 묶여 있는지 또는 실패했을 때 오류 메시지가 어떻게 보이는지를 빠뜨린다. 고객이 물어볼 때쯤이면, 담당자는 그 고객이 방금 읽은 것과 똑같은 공개 노트를 아무 우위 없이 읽고 있는 셈이다.&lt;/p&gt;
&lt;h2&gt;내부용 릴리스 노트는 고객용 노트가 말하지 않는 무엇을 말해야 하는가&lt;/h2&gt;
&lt;p&gt;고객용 노트가 의도적으로 빠뜨리는 운영상의 세부 사항이다. 어느 요금제나 계정이 그것을 갖는지. 무언가 잘못됐을 때 어떻게 보이는지, 그리고 그것을 마주친 고객에게 무엇을 말해야 하는지. 열려 있는 요청이나 티켓을 닫는지, 어떤 것을 닫는지, 관련 티켓을 다루는 담당자가 확인해야 한다는 것을 알 수 있도록. 질문이 노트가 다루는 범위를 넘어설 때 팀에서 누가 책임지는지. 이 중 어느 것도 회사 밖의 누군가가 한 번 읽도록 쓰인 고객용 버전에는 속하지 않는다. 이 모든 것이야말로 같은 질문에 일주일에 마흔 번 답하는 사람에게 정말로 필요한 것이다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;내부 메모: 대량 CSV 내보내기 (2026-09-08 출시)

- Team 및 Enterprise 요금제에서만. Free와 Pro는 변경 없음.
- 흔한 오류: 5만 행이 넘는 내보내기는 타임아웃된다; 알려진
  문제이며 수정은 별도로 추적 중. 고객에게 날짜 범위로
  필터링하라고 안내할 것.
- `bulk-export` 라벨이 붙은 열린 요청 14건을 닫는다. 답변
  템플릿은 공유 문서에 있음.
- 담당: platform 팀, 이 메모 범위를 벗어나는 것은 모두
  #platform-eng로.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;지원팀 담당자가 즉시 쓸 수 있는 네 줄이며, 그중 어느 것도 같은 기능에 대한 공개 체인지로그 항목에 속하지 않는다.&lt;/p&gt;
&lt;h2&gt;누가 이것을 써야 하며, 언제 써야 하는가&lt;/h2&gt;
&lt;p&gt;고객용 노트를 쓰는 사람이 보통 적임자인데, 이미 모든 맥락을 갖고 있기 때문이다. 하지만 하나의 문서가 두 독자층을 모두 상대하려 하는 대신, 별도의 짧은 작업이어야 한다. 둘을 합치면 내부 세부 사항으로 무거워진 고객용 노트가 나오거나, 정말로 유용하기에는 너무 다듬어진 내부용 노트가 나오는데, 실제로는 두 독자층을 동시에 상대하도록 하나의 문서를 조율하는 것보다 짧은 문서 두 개를 쓰는 편이 더 빠르다. 타이밍은 누가 썼는지보다 더 중요하다. 내부용 노트는 단 몇 시간이라도 고객용 노트보다 먼저 나와야 하는데, 지원팀이 고객과 같은 곳에서 변경 사항을 알게 되는 일이 결코 없도록 하기 위해서다.&lt;/p&gt;
&lt;h2&gt;지원팀이 티켓이 발생한 순간에 정말로 그것을 찾을 수 있으려면 어디에 있어야 하는가&lt;/h2&gt;
&lt;p&gt;티켓이 들어왔을 때 팀이 이미 찾아보는 곳이지, 아무도 스스로 열어볼 이유가 없는 별도의 체인지로그가 아니다. 공유 지식 베이스를 쓰는 지원팀은 그 노트가, 제품의 그 부분에 대한 티켓이 이미 라벨링되는 곳에서 링크된 형태로 거기에 있어야 한다. 공유 채널에서 활동하는 팀은 그것이 관련 있는 순간에 검색 가능한 형태로 거기에 게시되어 있어야 하며, 한 번 훑어보고 마는 일일 요약에 파묻혀 있어서는 안 된다. &lt;a href=&quot;https://changeloop.dev/blog/ko/product-update-email/&quot;&gt;타겟 알림 대 다이제스트&lt;/a&gt;에 나온 고객용 패턴이 여기에도 적용된다. 구체적이고 곧 닥칠 변경에 대한 내부 메모는 첫 티켓이 이미 존재한 뒤에 도착하는 주간 요약을 기다리지 말고 팀에 직접 도달해야 한다.&lt;/p&gt;
&lt;h2&gt;외부용과 같은 수준의 검토 엄격함이 필요한가&lt;/h2&gt;
&lt;p&gt;더 적게 필요하며, 이것은 의도된 것이다. 고객용 노트는 회사를 공개적으로 대표하며 세심한 편집 과정을 거칠 자격이 있다. 내부용 노트는 빠르고 구체적이기 위해 존재하며, 그것을 같은 다듬기 기준에 묶어두는 것은 보통 팀이 그것을 아예 쓰지 않게 만드는 바로 그 이유다. 출시 한 시간 전에 나오는 빠르고 다소 거친 내부 메모는, 첫 지원 티켓이 이미 당황한 채로 들어온 다음 날 도착하는 다듬어진 노트를 이긴다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;내부용 릴리스 노트도 고객용과 같은 승인 프로세스를 거쳐야 하는가?&lt;/strong&gt;
아니다. 더 가볍고 빠른 과정이 바로 그 목적이다. 같은 검토를 요구하면 당일에 나올 내부 메모가 다음 주 메모로 바뀌는데, 그때쯤이면 지원팀은 이미 그것 없이 질문에 답한 뒤다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;전담 내부 커뮤니케이션 역할이 없다면 누가 내부용 릴리스 노트를 책임져야 하는가?&lt;/strong&gt;
고객용 노트를 쓰는 사람이, 바로 뒤에 이어지는 두 번째의 짧은 과정으로서. 별도의 담당자가 필요한 것이 아니라, 고객용 노트를 릴리스가 만들어내는 유일한 산출물로 취급하지 않는 습관만 필요하다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;내부용 릴리스 노트도 자체 체인지로그나 아카이브가 필요한가?&lt;/strong&gt;
검색 가능한 곳이 아무도 스크롤하지 않는 시간순 아카이브보다 낫다. 지원팀이 이미 지식 베이스를 갖고 있다면, 노트는 출시일을 이미 아는 사람에게만 도움이 되는 별도의 내부 체인지로그가 아니라, 기능에 라벨링된 채로 거기에 속해야 한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;작은 변경에 대해 내부용 릴리스 노트를 건너뛰는 위험은 무엇인가?&lt;/strong&gt;
작은 변경이야말로 지원팀이 예고 없이 질문을 받는 바로 그런 것인데, 작은 변경은 회사 전체 공지를 받는 경우가 드물기 때문이다. 릴리스 노트의 규모는 변경의 규모에 맞춰 조정되어야 하며, 변경이 사소했다는 이유만으로 결코 0으로 떨어져서는 안 된다.&lt;/p&gt;
</content:encoded></item><item><title>모바일 앱 릴리스 노트: 글자 수 제한이 무엇을 잘라내는가</title><link>https://changeloop.dev/blog/ko/mobile-app-release-notes/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/mobile-app-release-notes/</guid><description>앱스토어와 플레이스토어는 눈에 보이는 몇 줄만 주고 링크는 허용하지 않는다. 웹 체인지로그에서 통하던 방식이 깨지므로 무엇을 의도적으로 자를지 설명한다.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;이 허브에서 릴리스 노트 작성에 대해 다룬 모든 내용은 완전히 통제할 수 있는 페이지를 전제로 한다. 원하는 길이, 작동하는 링크, 렌더링되는 서식 말이다. 모바일 앱의 릴리스 노트는 다른 누군가의 상자 안에서 산다. 애플은 대략 4,000자를 주지만 &amp;quot;더 보기&amp;quot;를 누르기 전까지는 처음 몇 줄만 보여준다. 구글도 비슷한 여유를 주지만 똑같이 실질적인 미리보기 문제가 있고, 두 플랫폼 모두 텍스트 안에 클릭 가능한 링크를 렌더링하지 않는다. &lt;a href=&quot;https://changeloop.dev/blog/ko/how-to-write-release-notes/&quot;&gt;사람들이 실제로 읽는 릴리스 노트 작성법&lt;/a&gt;에 나온 규칙, 무엇이 바뀌었고 독자가 무엇을 해야 하는지 말하라는 규칙은 여전히 적용되지만, 그것을 할 공간은 체인지로그 페이지가 허용하는 것의 일부에 불과하며, 잘라내는 일은 우연이 아니라 의도적이어야 한다.&lt;/p&gt;
&lt;h2&gt;눈에 보이는 미리보기에 실제로 들어가는 것은 무엇인가&lt;/h2&gt;
&lt;p&gt;기기와 글꼴 크기에 따라 대략 80에서 170자 정도인 처음 한두 줄이다, 독자가 펼치려고 탭하기 전까지. 이것이 릴리스 노트에서 누군가 나머지를 읽을지를 결정하는 부분의 전체 예산이며, 가장 중요한 문장이 가장 먼저 와야 한다는 뜻이다. 버전 번호도, 인사말도, 카테고리 제목도 아니다. &amp;quot;이번 버전의 새로운 점:&amp;quot;으로 시작하는 릴리스 노트는 독자에게 아무것도 알려주지 않는 네 단어에 이미 보이는 공간의 3분의 1을 써버린 것이다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;플랫폼&lt;/th&gt;
&lt;th&gt;대략적인 전체 한도&lt;/th&gt;
&lt;th&gt;&amp;quot;더 보기&amp;quot; 전 실질적인 미리보기&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;앱스토어 (iOS)&lt;/td&gt;
&lt;td&gt;약 4,000자&lt;/td&gt;
&lt;td&gt;2-3줄, 대략 80-170자&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;구글 플레이&lt;/td&gt;
&lt;td&gt;언어당 약 500자, 일부 필드는 더 짧음&lt;/td&gt;
&lt;td&gt;2-3줄, iOS와 비슷&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;둘 다&lt;/td&gt;
&lt;td&gt;릴리스 노트 필드에 클릭 가능한 링크 없음&lt;/td&gt;
&lt;td&gt;해당 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;&amp;quot;지금 무엇을 할 수 있고 무엇이 보장되는가&amp;quot;라는 규칙이 이 길이에서도 통하는가&lt;/h2&gt;
&lt;p&gt;통한다, 그리고 다르게가 아니라 더 엄격하게 통한다. 항목당 한 문장, 동사가 먼저, 서두 없이: &amp;quot;설정에서 데이터를 CSV로 내보내세요.&amp;quot;는 &amp;quot;사용자가 이제 데이터를 CSV 형식으로 내보낼 수 있는 기능을 추가했습니다&amp;quot;를 3분의 1의 단어로 같은 말을 함으로써 이긴다. 체인지로그 페이지 길이에서는 다소 장황한 문장이 독자에게 0.5초를 잃게 한다. 모바일 릴리스 노트 길이에서는 같은 장황함이 문장 전체를 눈에 보이는 미리보기 밖으로 밀어낼 수 있어서, 독자는 무엇이 바뀌었는지 알려줬을 동사를 아예 보지 못하게 된다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;나쁨, 미리보기를 서두에 낭비함:
&amp;quot;개선 사항으로 가득한 새 업데이트를 가져오게
되어 기쁩니다! 자세한 내용은 계속 읽어보세요.&amp;quot;

좋음, 첫 줄에 모든 가치가 담김:
&amp;quot;데이터를 CSV로 내보내세요. 다크 모드가 이제
시스템 설정을 따릅니다. 공유 링크를 열 때
발생하던 충돌을 수정했습니다.&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;웹 체인지로그 항목이라면 보통 남겨둘 것 중 무엇을 잘라내야 하는가&lt;/h2&gt;
&lt;p&gt;링크가 먼저다, 두 스토어 모두 그것을 클릭 가능하게 렌더링하지 않으므로 텍스트 속 URL은 독자가 다시 입력해야 할 죽은 무게이기 때문이다. 항목에 목적지가 필요하다면 대신 앱에서 무엇을 탭해야 하는지 말하라: &amp;quot;설정 &amp;gt; 검색 아래 새 필터를 확인하세요&amp;quot;는 통하지만 &amp;quot;example.com/blog/filters에서 더 읽어보세요&amp;quot;는 이 표면에서는 통하지 않는다. 둘째, 조건부이거나 특정 독자에게만 해당하는 것 전부다. 웹 체인지로그는 &amp;quot;API를 사용한다면 이것이 당신에게 해당됩니다&amp;quot;라고 말할 수 있지만, 스토어 목록은 설치한 모든 사용자에게 동시에 도달하므로 조건부 줄은 해당되지 않는 95%에게는 잡음으로 읽힌다. 조건부 세부 사항은 대신 실제로 관련된 계정에만 트리거되는 앱 내 메시지에 넣어라.&lt;/p&gt;
&lt;h2&gt;모든 릴리스가 자체 노트를 가져야 하는가, 아니면 &amp;quot;버그 수정 및 성능 개선&amp;quot;을 재사용해도 괜찮은가&lt;/h2&gt;
&lt;p&gt;정말로 그러한 릴리스에는 재사용해도 되지만, 그것이 실제로 얼마나 자주 사실인지 감사하라. &lt;a href=&quot;https://changeloop.dev/blog/ko/how-to-write-release-notes/&quot;&gt;릴리스 노트 작성법&lt;/a&gt;은 그 문구가 독자를 위해서가 아니라 내부에서 쓰인 노트를 드러낸다는 점을 이미 다룬다. 모바일에서는 이것이 이중으로 해를 끼치는데, 스토어 릴리스 노트는 일부 사용자가 업데이트 사이에 무언가를 볼 수 있는 몇 안 되는 곳 중 하나이기 때문이고, &amp;quot;버그 수정 및 성능 개선&amp;quot;이 길게 이어지면 앱이 변하지 않는 것처럼 읽혀서, 그 기간 동안 노트가 아예 없는 것보다 더 나쁜 인상을 준다.&lt;/p&gt;
&lt;h2&gt;릴리스 노트는 사람들이 앱을 업데이트할지 여부에 아예 영향을 미치는가&lt;/h2&gt;
&lt;p&gt;설득보다는 가시성을 통해 간접적으로 영향을 미친다. 대부분의 사용자는 자동으로 업데이트하고 업데이트 전에 노트를 읽는 일이 없다. 노트는 업데이트를 수동으로 확인하는 소수, 그리고 스토어 목록의 이력을 훑어보는 리뷰어나 언론에게 가장 중요하다. 그 작은 독자층을 위해 쓰는 것도 여전히 값어치를 하는데, 구체적이고 날짜가 찍힌 항목들의 실제 이력이 있는 목록은 활발히 관리되는 앱처럼 읽히고, &amp;quot;버그 수정 및 성능 개선&amp;quot;만 1년 이어진 목록은 그 기간 실제로 얼마나 많은 것이 출시되었든 그렇게 읽히지 않기 때문이다.&lt;/p&gt;
&lt;h2&gt;사용자에게 선택권이 없는 이유를 노트가 설명해야 하는 강제 업데이트는 어떤가&lt;/h2&gt;
&lt;p&gt;이유와 기한을 다른 무엇보다 먼저 첫 줄에 밝혀라, 강제 업데이트는 독자가 읽기 시작하기도 전에 이미 짜증이 난 유일한 경우이기 때문이다. &amp;quot;데이터 동기화를 계속하려면 이 업데이트가 필요합니다. 중단을 피하려면 [날짜]까지 업데이트하세요.&amp;quot;는 무엇을 해야 하고 왜인지를 한 문장으로 말한다. 그 이유를 관련 없는 기능 노트 세 줄 아래에 묻어버리면 앱이 불편한 부분을 숨기는 것처럼 읽힌다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;모바일 릴리스 노트는 같은 릴리스의 웹 체인지로그와 일치해야 하는가?&lt;/strong&gt;
같은 근본적인 변경 사항을 다뤄야 하지만 토씨 하나까지 같을 필요는 없다. 웹 체인지로그는 완전한 설명을 감당할 수 있지만, 모바일 노트는 동사가 먼저 오는 한 문장으로 압축된 같은 사실이 필요하며, 이것은 보통 복사가 아니라 다시 쓰기를 의미한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;지원하는 언어마다 모바일 릴리스 노트를 현지화할 가치가 있는가?&lt;/strong&gt;
있다, 웹 체인지로그보다 더 그렇다, 스토어 목록이 종종 일부 사용자가 세션 사이에 보는 유일한 현지화된 표면이기 때문이며, 두 플랫폼 모두 번역 자체를 넘어서는 추가 엔지니어링 작업 없이 로케일별 릴리스 노트를 지원한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;간결함을 강제하는 한도가 없다면 모바일 릴리스 노트는 얼마나 길어야 하는가?&lt;/strong&gt;
그래도 짧아야 한다. iOS의 4,000자 상한이 실제 제약인 경우는 드물다. 실제 제약은 2-3줄 미리보기이며, 그 미리보기가 보여주는 것을 넘어서 쓰는 것은 그저 중요한 부분을 읽는 사람이 줄어든다는 뜻일 뿐이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;릴리스 노트는 눈에 보이는 텍스트에 버전 번호가 필요한가?&lt;/strong&gt;
아니다. 스토어는 이미 노트 옆에 버전 번호를 보여준다. 텍스트 안에서 그것을 반복하는 것은 독자가 이미 눈앞에 가지고 있는 정보에 눈에 보이는 글자를 쓰는 셈이다.&lt;/p&gt;
</content:encoded></item><item><title>모노레포 체인지로그: 하나로 합칠까, 패키지마다 따로 둘까</title><link>https://changeloop.dev/blog/ko/monorepo-changelogs/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/monorepo-changelogs/</guid><description>모노레포는 저장소 전체를 위한 체인지로그 하나나 패키지마다 하나를 둘 수 있다. 잘못 고르면 릴리스가 너무 시끄럽거나 흩어진다. 기준은 구조가 아니라 독자다.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;모노레포는 하나의 저장소 안에 별도로 배포되는 여러 가지를 담고 있으며, 체인지로그는 먼저 하나의 질문에 답해야 한다. 독자가 신경 쓰는 것이 저장소 자체인지, 아니면 그 안의 특정 패키지인지. 대부분의 팀은 이것을 의도적으로 결정한 적이 없다. 저장소가 하나이기 때문에 체인지로그도 하나로 시작하고, 시간이 지나면서 패키지를 계속 추가하다가, CLI를 쓰는 사람이 자신의 수정 사항이 담긴 항목을 찾으려고 관련 없는 백엔드 항목 마흔 개를 지나쳐야 하는 로그로 끝나게 된다. 올바른 형태를 결정하는 것은 저장소의 구조가 아니라, 누가 그 로그를 읽고 이미 무엇을 찾으려 하는지다.&lt;/p&gt;
&lt;h2&gt;모노레포의 체인지로그는 단일 저장소의 것과 무엇이 다른가&lt;/h2&gt;
&lt;p&gt;단일 저장소의 체인지로그에는 암묵적인 독자층이 있다. 그 저장소가 만드는 유일한 것을 사용하는 모든 사람이다. 모노레포의 독자층은 패키지별로 나뉘고, 같은 저장소 안의 패키지들은 흔히 서로 다른 일정으로, 서로 다른 소비자에게, 서로 다른 안정성 수준으로 출시된다. 레지스트리에 게시되는 라이브러리와 내부 관리 도구가 같은 모노레포에 함께 살면서도, 체인지로그를 읽는 사람 입장에서는 거의 공통점이 없을 수 있다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;저장소 형태&lt;/th&gt;
&lt;th&gt;전형적인 독자&lt;/th&gt;
&lt;th&gt;어울리는 체인지로그&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;배포 가능한 앱 하나&lt;/td&gt;
&lt;td&gt;그 제품을 쓰는 모든 사람&lt;/td&gt;
&lt;td&gt;저장소 전체를 위한 로그 하나&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;라이브러리 워크스페이스 (여러 개의 게시된 패키지)&lt;/td&gt;
&lt;td&gt;특정 패키지에 의존하는 사람&lt;/td&gt;
&lt;td&gt;패키지마다 로그 하나&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;앱 더하기 내부 도구&lt;/td&gt;
&lt;td&gt;겹치지 않는 두 독자층&lt;/td&gt;
&lt;td&gt;폴더가 아니라 독자층에 따라 분리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;앱 더하기 자체 SDK&lt;/td&gt;
&lt;td&gt;제품 사용자, 그리고 SDK 통합자&lt;/td&gt;
&lt;td&gt;두 개의 로그: 제품용, SDK용&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;모든 패키지가 자기만의 체인지로그를 가져야 하는가&lt;/h2&gt;
&lt;p&gt;독립된 독자층을 가진 패키지만 그렇다. 레지스트리에 게시되는 패키지는 자기만의 로그가 필요한데, 그것을 설치하는 사람은 저장소의 다른 무언가를 읽을 이유가 없고, &lt;a href=&quot;https://lerna.js.org/&quot;&gt;Lerna&lt;/a&gt;나 Changesets 같은 모노레포 릴리스 도구는 패키지마다 &lt;code&gt;CHANGELOG.md&lt;/code&gt;를 그 &lt;code&gt;package.json&lt;/code&gt; 옆에 작성하기 때문이다. 같은 저장소에 이미 존재하는 앱이라는 소비자 하나만 있는 내부 유틸리티는 별도의 로그가 필요하지 않다. 그 변경 사항을 그 앱의 항목에 포함시키는 것이 팀 밖의 누구도 열어보지 않는 두 번째 파일보다 더 유용하다.&lt;/p&gt;
&lt;p&gt;테스트는 어떤 항목이든 애초에 체인지로그에 속하는지를 결정하는 것과 동일하다. 독자가 그것을 알아채거나 신경 쓸 것인가, 그리고 그것을 알고 나서 행동할 수 있는가. 이것을 폴더가 아니라 패키지 단위로 적용하면, 패키지 열두 개짜리 저장소가 진짜 체인지로그 두 개와 아예 필요 없는 패키지 열 개로 끝날 수도 있다.&lt;/p&gt;
&lt;h2&gt;어떤 패키지가 어떤 체인지로그 항목을 일으켰는지 어떻게 아는가&lt;/h2&gt;
&lt;p&gt;각 항목을 커밋이 어떤 파일을 건드렸는지 나중에 조사하는 것이 아니라, 그 항목이 쓰이는 순간에 해당 패키지로 표시하라. 공유되는 내부 라이브러리를 고치는 커밋은 거기에 의존하는 모든 패키지에서 체인지로그 항목을 만들어낼 수 있으며, 파일 경로만으로는 이 하위 항목들 중 어떤 것을 독자가 정말로 봐야 하는지 말해줄 수 없다. &amp;quot;이것은 패키지 A를 쓰는 사람에게는 보이고 패키지 B를 쓰는 사람에게는 보이지 않는다&amp;quot;라고 결정할 수 있는 것은 사람뿐이다. &lt;a href=&quot;https://changeloop.dev/blog/ko/conventional-commits-changelog/&quot;&gt;Conventional commits&lt;/a&gt;는 각 커밋에서 패키지를 명시함으로써 여기서 기계적으로 도움을 주지만, 스코프는 여전히 초안 하나만 만들어낸다. 그 글과 같은 두 단계 규칙이 패키지 단위로도 적용된다. 올바른 스코프를 가진 초안도 그 패키지의 실제 독자를 위해 표현되기 전에는 사람의 손길이 여전히 필요하다.&lt;/p&gt;
&lt;h2&gt;공유 체인지로그가, 단일 저장소의 체인지로그에는 필요 없는 무엇을 필요로 하는가&lt;/h2&gt;
&lt;p&gt;각 항목의 맨 앞, 설명 이전에 오는 패키지 라벨이다. 그래야 로그를 훑어보는 독자가 한 번 훑는 것만으로 자신과 관계없는 모든 것을 건너뛸 수 있다. 그 라벨이 없으면 공유 로그는 무작위 피드처럼 읽히고, 하나의 패키지에 관심 있는 독자는 어떤 줄이 중요한지 외우는 것 말고는 그것을 걸러낼 방법이 없는데, 첫 주가 지나면 아무도 그렇게 하지 않는다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;## 2026-09-07

### [cli] 추가됨
- `acme push --dry-run`이 실제로 보내지 않고 무엇이
  보내질지 보여준다.

### [core] 수정됨
- 빈 본문을 반환하는 성공한 요청에서 재시도 백오프가 더 이상
  초기화되지 않는다.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;두 개의 항목, 두 개의 독자층, 구분하는 데 한 번 훑어보면 충분하다. &lt;a href=&quot;https://github.com/changesets/changesets/blob/main/docs/intro-to-using-changesets.md&quot;&gt;Changesets&lt;/a&gt; 방식의 워크플로는 이 표시 작업을 릴리스 프로세스에 직접 내장한다. 기여자가 자신의 변경 사항 옆에 패키지 스코프를 가진 짧은 노트를 쓰고, 도구는 릴리스 시점에 그 노트들로부터 패키지별 체인지로그와 버전 상승을 조립한다. 통합된 커밋 이력에서 나중에 패키지 경계를 재구성하려 시도하는 대신 말이다.&lt;/p&gt;
&lt;h2&gt;버전 관리는 모노레포 체인지로그와 어떻게 연결되는가&lt;/h2&gt;
&lt;p&gt;독립적으로 버전이 매겨지는 패키지들은 자기만의 버전 번호를 갖기 때문에 자기만의 체인지로그가 필요하며, 공유 체인지로그는 &amp;quot;패키지 A는 2.1에서 2.2로 올라갔는데 패키지 B는 1.4에 머물렀다&amp;quot;를 하나의 파일 안에 두 개의 로그가 되지 않고서는 표현할 수 없다. &lt;a href=&quot;https://changeloop.dev/blog/ko/semantic-versioning-changelog/&quot;&gt;시맨틱 버저닝과 당신의 체인지로그&lt;/a&gt;가 버전 번호 자체가 체인지로그 카테고리에 어떻게 매핑되어야 하는지를 다룬다. 모노레포에서는 그 매핑을 패키지 단위로 적용해야 하는데, 한 패키지의 breaking change가 그것에 의존하지 않는 자매 패키지에는 breaking change가 아니기 때문이다.&lt;/p&gt;
&lt;p&gt;여러 내부 패키지로 만들어졌더라도 하나의 제품을 하나의 배포 단위로 출시하는 저장소는 이런 문제를 겪지 않는다. 패키지들은 항상 함께 출시되기 때문에 버전을 공유하며, 체인지로그 하나면 충분하다.&lt;/p&gt;
&lt;h2&gt;git 태그는 모노레포에 어떻게 맞아 들어가는가&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://changeloop.dev/blog/ko/git-tags-releases-changelog/&quot;&gt;git 태그, 릴리스, 그리고 당신의 체인지로그&lt;/a&gt;에 나온 것과 같은 규칙이 패키지 단위로 적용되어 그대로 성립한다. 자기만의 버전을 가진 패키지는 자기만의 태그 접두사가 필요하며, 보통 어떤 패키지에 속하는지 말해줄 수 없는 벌거벗은 &lt;code&gt;v1.4.0&lt;/code&gt; 대신 &lt;code&gt;패키지이름@1.4.0&lt;/code&gt;이 쓰인다. 벌거벗은 버전 번호로만 태그가 붙은 모노레포는 나중에 &amp;quot;&lt;code&gt;cli&lt;/code&gt;가 2.2를 출시했을 때 &lt;code&gt;core&lt;/code&gt;에는 무엇이 있었는가&amp;quot;에 답할 수 없는데, 그 태그가 실제로 어느 패키지에 속했는지를 디스크에 아무것도 기록해두지 않았기 때문이다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;모노레포 안의 모든 패키지마다 별도의 체인지로그가 필요한가?&lt;/strong&gt;
독립된 독자층을 가진 패키지만 그렇다, 보통 레지스트리에 게시되는 것은 무엇이든 해당한다. 같은 저장소에 이미 존재하는 내부 소비자가 하나뿐인 패키지는 자기만의 로그를 유지하는 대신 그 소비자의 로그에 합류할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;체인지로그 항목을 올바른 패키지로 표시하는 것은 무엇인가?&lt;/strong&gt;
변경된 파일 경로에 대한 자동 스캔이 아니라, 항목을 쓰는 사람이 그것을 쓰는 그 순간이다. 공유 라이브러리의 변경은 거기에 의존하는 각 패키지에서 서로 다른 항목을 만들어낼 수 있으며, 그 하위 항목 각각이 실제로 무엇을 말해야 하는지는 오직 사람만이 결정할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;모노레포는 모든 것에 하나의 버전 번호를 써야 하는가?&lt;/strong&gt;
모든 패키지가 항상 나머지와 함께 출시되는 경우에만 그렇다. 패키지들이 언젠가 독립적으로 게시된다면 독립된 버전이 필요하고, 독립된 버전은 의미가 통하려면 독립된 체인지로그가 필요하다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;모노레포 체인지로그 도구가 사람이 편집하는 단계를 대체하는가?&lt;/strong&gt;
아니다. Changesets 같은 도구는 릴리스 시점에 패키지별 노트를 모으고 조립하는 작업을 자동화한다. 노트 자체는, 기여자가 아니라 독자의 언어로 쓰인 채로, 다른 어떤 체인지로그 파이프라인에서와 마찬가지로 여전히 사람의 몫으로 남는다.&lt;/p&gt;
</content:encoded></item><item><title>새 기능을 어떻게 발표해야 하는가 (침묵 없이)</title><link>https://changeloop.dev/blog/ko/new-feature-announcement/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/new-feature-announcement/</guid><description>대부분의 기능 발표는 아무도 두 번 읽지 않는 채널에서 조용히 죽는다. 어디서 발표하고 무엇을 먼저 말할지, 요청했던 사람에게 어떻게 닿을지 설명한다.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;대부분의 기능 발표는 아무도 두 번 읽지 않는 채널에서 죽는다. 스크롤을 지나쳐 사라지는 트윗, 구독자가 그 주에 받은 다른 열두 통 아래 묻힌 출시일 이메일, 팀 절반이 몇 달 전에 음소거한 채널의 슬랙 메시지. 기능은 출시되었다. 그것을 썼을 사람들 대부분은 몰랐다. 이것을 고치는 일은 더 나은 발표문을 쓰는 것보다는 올바른 독자에게 올바른 채널을 고르는 것, 그리고 명시적으로 요청한 사람들이 일반적인 메시지를 알아채기를 기대하는 대신 그들에게 직접 닿는 것에 더 가깝다.&lt;/p&gt;
&lt;h2&gt;새 기능은 실제로 어디에서 발표되어야 하는가&lt;/h2&gt;
&lt;p&gt;한 곳 이상에서, &amp;quot;모두가 같은 채널을 읽는다&amp;quot;는 결코 사실이 아니기 때문이다. 체인지로그나 피드 항목은 자신의 속도로 확인하며 영구적이고 날짜가 적힌 기록을 원하는 독자를 위한 것이다. 앱 내 알림은 이미 제품을 쓰고 있고 그 기능이 존재한다는 걸 알면 오늘 당장 쓸 독자를 위한 것이다. 이메일은 현재 제품에 없지만 알맞은 업데이트를 위해 돌아올 독자를 위한 것이다. 소셜 미디어는 거의 타겟팅 없이 기존 사용자를 넘어서는 도달을 위한 것이다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;채널&lt;/th&gt;
&lt;th&gt;가장 적합한 대상&lt;/th&gt;
&lt;th&gt;약점&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;체인지로그 / 피드&lt;/td&gt;
&lt;td&gt;영구 기록; 자신의 속도로 확인하는 독자&lt;/td&gt;
&lt;td&gt;수동적; 확인하지 않는 사람에게는 아무 소용없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;앱 내 알림&lt;/td&gt;
&lt;td&gt;이미 있고 오늘 행동할 사용자&lt;/td&gt;
&lt;td&gt;지금 로그인하지 않은 사람에게는 닿지 않음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;이메일&lt;/td&gt;
&lt;td&gt;비활성 상태지만 이것 때문에 돌아올 사용자&lt;/td&gt;
&lt;td&gt;다른 메일 아래 쉽게 묻힘; 진짜 제목이 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;소셜 미디어&lt;/td&gt;
&lt;td&gt;기존 사용자를 넘어서는 도달&lt;/td&gt;
&lt;td&gt;거의 타겟팅 없음; 짧은 수명&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;넷 중 어느 것도 혼자서는 충분하지 않다. &lt;a href=&quot;https://changeloop.dev/blog/ko/what-is-a-changelog/&quot;&gt;체인지로그&lt;/a&gt;는 크기와 상관없이 모든 릴리스를 담아야 하는 유일한 문서다. 나머지 모든 것이 다시 참조하는 기록이기 때문이다. 나머지 셋은 그 위에 더해지는 증폭이며, 기능이 실제로 얼마나 큰지에 따라 선택된다.&lt;/p&gt;
&lt;h2&gt;발표는 무엇을 먼저 말해야 하는가&lt;/h2&gt;
&lt;p&gt;메커니즘이 아니라 결과다. &amp;quot;보고서 엔드포인트에 캐시 레이어를 추가했다&amp;quot;는 팀이 무엇을 만들었는지 설명한다. &amp;quot;보고서가 이제 1초 안에 로드된다&amp;quot;는 독자에게 무엇이 바뀌었는지 설명하며, 바로 이 문장이 클릭을 얻는다. 세 번째 절이 아니라 첫 번째 절에서 &amp;quot;이게 나한테 무슨 소용인가&amp;quot;에 답하기 때문이다. 메커니즘은 체인지로그 항목이나 상세 페이지에 속하지, 제목에 속하지 않는다.&lt;/p&gt;
&lt;p&gt;형용사보다 구체성을 앞세워라. &amp;quot;더 빠르고 더 강력한 보고서 경험&amp;quot;은 독자에게 행동할 만한 어떤 것도 말해주지 않는다. &amp;quot;보고서가 이제 1초 안에 로드되고 상태로 필터링할 수 있다&amp;quot;는 정확히 무엇이 바뀌었고 무엇을 시도해야 하는지 말해준다. 두 번째 버전은 더 믿을 만하게도 느껴지는데, 막연한 주장은 구체적으로 할 말이 없을 때 마케팅 문구가 들리는 것과 정확히 똑같이 들리기 때문이다.&lt;/p&gt;
&lt;h2&gt;제품 업데이트 이메일과는 어떻게 다른가&lt;/h2&gt;
&lt;p&gt;겹치지만 동일하지는 않다. &lt;a href=&quot;https://changeloop.dev/blog/ko/product-update-email/&quot;&gt;제품 업데이트 이메일&lt;/a&gt;이 빈도, 제목, 그리고 다이제스트가 단발성 발송을 이길 때를 포함해 이메일 채널을 구체적으로 다룬다. 새 기능 발표는 근본적인 사건이다. 이메일은 그것을 담을 수 있는 위 네 채널 중 하나이며, 기능이 다음 다이제스트에 실리는 대신 전용 발송을 정당화할 만큼 클 때 선택된다. 작은 기능은 체인지로그 항목과 어쩌면 앱 내 알림을 받을 만하다. 중요한 기능은 시간을 맞춘 네 채널 모두를 받을 만하다.&lt;/p&gt;
&lt;h2&gt;그것을 요청한 바로 그 사람들에게는 어떻게 닿는가&lt;/h2&gt;
&lt;p&gt;이것은 노력 대비 효과가 가장 좋은 발표이며, 거의 모든 팀이 건너뛴다. 열 명의 고객이 이름으로 기능을 요청했다면, 그 열 명은 나가는 어떤 더 넓은 발표와도 상관없이 출시되는 순간 직접적이고 개인적인 메모를 받을 만하다. &lt;a href=&quot;https://changeloop.dev/blog/ko/customer-feedback-loop/&quot;&gt;고객과의 피드백 순환 닫기&lt;/a&gt;가 그 메커니즘을 완전히 다룬다. 여기서 요약하면, 이것은 원래 요청이 요청한 사람과 계속 연결되어 있을 때만 작동하는데, 이는 발표 문제라기보다는 &lt;a href=&quot;https://changeloop.dev/blog/ko/feature-request-tracking/&quot;&gt;추적 문제&lt;/a&gt;에 가깝다. changeloop에서는 위젯 피드백이 GitHub 이슈가 되고 병합된 pull request가 그것을 닫으면(&lt;code&gt;fixes #142&lt;/code&gt;), 체인지로그 항목을 승인할 때 그 이슈에 &amp;quot;Shipped — &lt;title&gt;&amp;quot; 댓글이 한 번 게시되어 실시간 항목으로 다시 연결되고, 피드백을 보낸 사람은 위젯에서 출시된 항목을 보게 된다. 누군가 기억해서 말해줄 필요가 없다. 손으로 접수한 이슈, 그리고 GitLab이나 Bitbucket 저장소는 이 댓글을 받지 않는다.&lt;/p&gt;
&lt;h2&gt;항목 자체는 어떻게 쓰는가&lt;/h2&gt;
&lt;p&gt;다른 릴리스 노트 항목과 같은 원칙이다. 독자가 이제 할 수 있는 것으로 시작하고, 필요한 설정으로 이어가고, 내부적인 정당화는 건너뛴다. &lt;a href=&quot;https://changeloop.dev/blog/ko/how-to-write-release-notes/&quot;&gt;릴리스 노트 쓰는 법&lt;/a&gt;이 완전한 방법을 다룬다. 새 기능 발표는 판돈이 가장 큰 경우다. 제품의 체인지로그를 한 번도 본 적 없는 누군가에 의해 캡처되고, 전달되고, 읽힐 가능성이 가장 높은 항목이기 때문이다.&lt;/p&gt;
&lt;h2&gt;언제 널리 발표하지 말아야 하는가&lt;/h2&gt;
&lt;p&gt;기능이 아직 계정 일부에만 롤아웃 중일 때, 정말로 베타일 때, 또는 가격이나 접근 제한 때문에 넓은 발표를 읽는 독자 열 명 중 아홉 명이 아직 쓸 수 없을 때다. 열 명 중 아홉 명이 쓸 수 없는 기능의 넓은 발표는 미끼처럼 읽히며, 지금의 관심보다 다음 발표에 대한 신뢰를 더 많이 태워버린다. 해법은 침묵이 아니라 범위다. 자격이 있는 계정에는 직접 알리고, 가용성이 발표를 따라잡을 때까지 넓은 채널을 미뤄라.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;모든 새 기능이 자체 발표를 받을 만한가?&lt;/strong&gt;
모두 체인지로그 항목을 받을 만하다. 누군가 제품을 쓰는 방식을 바꿀 만큼 중요하거나 이름으로 명시적으로 요청된 것만이 이메일이나 소셜 미디어 같은 더 넓은 채널을 받을 만하다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;작은 기능에 가장 좋은 채널은 무엇인가?&lt;/strong&gt;
체인지로그만, 그리고 사용자가 이미 있는 흐름 안에서 기능을 발견할 수 있다면 앱 내 알림도. 이메일과 소셜 미디어는 관심을 요청할 만한 기능에 대해 그만한 가치가 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;구체적으로 요청한 사람들에게는 기능을 어떻게 발표하는가?&lt;/strong&gt;
등록되는 순간부터 요청을 요청한 사람과 연결된 상태로 유지하고, 어떤 더 넓은 발표와도 별개로 출시 시 개별적으로 알려라. 요청한 사람이 스스로 확인할 수 있는 공유 상태 라벨도 애초에 필요한 개별 메시지 수를 줄여준다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;기능 발표에 스크린샷이 필요한가?&lt;/strong&gt;
시각적인 모든 것에는 그렇다. 설명은 되었지만 보이지 않은 기능은 독자가 미리보기를 볼 수 있는 기능보다 훨씬 더 자주 건너뛰어진다. API나 백엔드 기능이라면 짧은 코드 예제가 UI 변경에 대한 스크린샷과 같은 일을 한다.&lt;/p&gt;
</content:encoded></item><item><title>계속 쌓이는 기능 요청에 우선순위를 매기는 방법</title><link>https://changeloop.dev/blog/ko/prioritizing-feature-requests/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/prioritizing-feature-requests/</guid><description>백로그를 추적하고 묶고 라벨을 붙여도 어떤 요청을 먼저 내보낼지라는 질문은 남는다. 쓸 만한 프레임워크와 한계, 투표 수가 감추는 것을 짚어본다.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;기능 요청을 추적하는 것은 그것들이 어디에 있는지를 해결해준다. 어떤 것을 먼저 내보낼지는 해결해주지 않으며, 팀이 실제로 막히는 지점은 바로 이 두 번째 질문이다. 그룹으로 묶이고 라벨이 붙은 요청 삼백 개짜리 백로그도 여전히 결정 규칙이 필요한데, &amp;quot;가장 많이 요청받은 것을 만들어라&amp;quot;는 두 요청이 비슷할 때, 그리고 세 번째 요청에 목소리 큰 지지자가 있을 때까지만 통하기 때문이다. 그런 일은 대부분의 주에 일어난다. 아래의 프레임워크들은 같은 질문에 대한 경쟁하는 답이 아니다. 각각은 서로 다른 유형의 요청에 맞으며, 모든 것에 하나만 쓰는 것이 보통 진짜 실수다.&lt;/p&gt;
&lt;h2&gt;기능 요청 우선순위 매기기는 로드맵 우선순위 매기기와 무엇이 다른가&lt;/h2&gt;
&lt;p&gt;로드맵 결정은 전략에서 시작해서 무엇을 만들지 묻는다. 기능 요청 결정은 이미 존재하는 수요에서 시작해서 그것에 대응할지 묻는데, 이 둘은 충분히 자주 서로 다른 방향으로 당기기 때문에 어떤 요청은 수요가 높으면서도 만들기에는 잘못된 것일 수 있고, 수요가 낮으면서도 전략적 계정을 열어준다는 이유로 그럴 가치가 있을 수 있다. 모든 요청을 로드맵 투표처럼 다루는 것은 이 확인 과정을 건너뛴다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;프레임워크&lt;/th&gt;
&lt;th&gt;무엇을 가중하는가&lt;/th&gt;
&lt;th&gt;어디서 무너지는가&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;순수 요청 수&lt;/td&gt;
&lt;td&gt;얼마나 많은 사람이 요청했는가&lt;/td&gt;
&lt;td&gt;실제 수요보다 기억하기 쉬운 이름을 우대한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RICE&lt;/td&gt;
&lt;td&gt;도달 범위, 영향, 확신, 노력&lt;/td&gt;
&lt;td&gt;새로 들어온 요청에는 아무도 갖고 있지 않은 추정치가 필요하다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;매출 가중&lt;/td&gt;
&lt;td&gt;계정 가치에 따라 누가 요청했는가&lt;/td&gt;
&lt;td&gt;아직 큰 가치가 없는 계정의 요청을 무시한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;공개 투표&lt;/td&gt;
&lt;td&gt;눈에 보이는, 낮은 노력의 신호&lt;/td&gt;
&lt;td&gt;어디를 봐야 할지 이미 아는 사용자에게만 도달한다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;RICE란 무엇이고, 기능 요청에도 통하는가&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.intercom.com/blog/rice-simple-prioritization-for-product-managers/&quot;&gt;RICE&lt;/a&gt;는 아이디어를 도달 범위, 영향, 확신, 노력으로 점수 매긴 다음, 앞의 셋을 넷째로 나누어 비교 가능한 숫자를 얻는다. 이것은 팀이 이미 믿고 있는 로드맵 아이디어를 위해 만들어졌으며, 어려운 부분은 서로 다른 베팅들을 비교하는 것이다. 기능 요청은 이미 도달 범위 숫자, 즉 요청한 사람 수를 갖고 시작하는데, 이것은 갓 나온 로드맵 아이디어가 보통 갖는 도달 범위보다 더 구체적이다. RICE가 요청과 마찰을 빚는 지점은 확신과 영향이다. 팀은 요청이 진짜라고 확신하면서도, 그것이 지표를 얼마나 움직일지에 대한 근거는 없을 수 있는데, 이미 이름과 실제 사용자의 흔적을 가진 요청의 &amp;quot;영향&amp;quot;은 방 밖의 아무도 아직 보지 못한 아이디어의 영향과는 다른 종류의 추정이기 때문이다.&lt;/p&gt;
&lt;p&gt;RICE는 진지하게 고려되고 있으면서 아직 결정되지 않은 요청에 써라. 들어오는 모든 요청에 적용하지는 말라. 점수 매기는 노력은 동점자를 가려낼 만큼 가까운 요청들에서만 값어치를 한다.&lt;/p&gt;
&lt;h2&gt;매출로 가중해야 하는가, 아니면 누가 요청했는지로 가중해야 하는가&lt;/h2&gt;
&lt;p&gt;누가 요청했는지로 가중하되, 매출만으로는 안 된다. 갱신이 가까운 계정, 이미 한 번 에스컬레이션한 계정, 그리고 그 요청이 진행 중인 거래를 열어주는 계정은 단순한 매출 숫자 하나로는 담아낼 수 없는 긴급성을 지니며, 체험판 가입에서 온 요청도 곧 매출이 될 결정을 막고 있다면 여전히 중요할 수 있다. 매출 가중은 이 모든 방법 중 계산하기 가장 쉬운 것이며, 바로 그래서 과신하기도 가장 쉽다. 진짜 이해관계가 없는 계정에서 오는 소음을 정확히 걸러내는 동시에, 아직 파이프라인에 있는 훨씬 더 큰 계정을 데려올 요청을 똑같이 쉽게 낮춰 평가할 수도 있다.&lt;/p&gt;
&lt;h2&gt;투표는 실제로 어떤 역할을 하는가&lt;/h2&gt;
&lt;p&gt;이미 존재하는 요청에는 저렴하고 지속적인 신호지만, 애초에 어떤 요청이 존재해야 하는지를 발견하는 데는 나쁜 방법이다. 투표 수는 이미 그 요청을 찾아내서 클릭할 가치가 있다고 판단한 사용자에게만 도달하는데, 이것은 공개 로드맵의 투표 합계가 수요만큼이나 가시성도 반영한다는 뜻이다. 목록 상단 근처의 오래된 요청은 부분적으로 찾기 쉽다는 이유만으로 계속 투표를 모으고, 그만큼 진짜인 더 새로운 요청은 0에서 시작한다. &lt;a href=&quot;https://changeloop.dev/blog/ko/public-roadmap/&quot;&gt;공개 로드맵&lt;/a&gt; 글은 로드맵에서 투표를 아예 빼자고 주장한다. 투표를 순서대로 쌓아 올리는 순위표가 아니라, 그룹으로 묶고 최신성으로 가중해야 하는 신호로 다뤄라.
&lt;a href=&quot;https://changeloop.dev/blog/ko/feedback-signal-quality/&quot;&gt;지원 티켓 대 기능 요청&lt;/a&gt;은 투표 수의 또 다른 사각지대를
다룬다. 그것을 마주치는 사용자가 게시판을 결코 찾지 못한다면 진짜 격차는 투표를 거의 만들어
내지 못할 수 있는 반면, 지원팀에서는 시끄럽게 나타난다.&lt;/p&gt;
&lt;h2&gt;가장 목소리 큰 고객이 언제 이기며, 그것은 문제인가&lt;/h2&gt;
&lt;p&gt;때로는 그렇고, 아무도 그것을 알아채지 못할 때만 문제가 된다. 자주 에스컬레이션하고, 상세한 티켓을 쓰고, 팀 안의 누군가와 직접 연락선이 있는 고객은 똑같이 타당한 요청을 가진 더 조용한 고객보다 자신의 요청이 더 빨리 검토되는 것을 보게 되며, 그것을 한 번도 확인하지 않는 우선순위 결정 프로세스는 가장 강한 사례를 가진 사람이 아니라 가장 끈질기게 밀어붙이는 사람을 체계적으로 편애하게 된다. 목소리 큰 고객은 고쳐야 할 문제가 아니다. 그들의 요청은 흔히 정말로 중요하다. 고쳐야 할 것은 습관이다. 주기적으로 출처별로 백로그를 훑어보고, 같은 소수의 계정이 최근 출시된 것의 대부분을 설명하는지 확인하고, 그것이 실제 수요가 있는 곳과 맞는지 자문하는 것이다.&lt;/p&gt;
&lt;h2&gt;우선순위 결정은 어떻게 답변으로 바뀌는가&lt;/h2&gt;
&lt;p&gt;여기서 내려지는 모든 결정은 승자와 패자를 함께 만들어내며, 둘 다 설명 없는 상태 변경이 아니라 실제 논리를 명시한 답변을 받을 자격이 있다. &lt;a href=&quot;https://changeloop.dev/blog/ko/declining-feature-requests/&quot;&gt;기능 요청을 거절하는 방법&lt;/a&gt;이 진 요청에게 무엇을 말해야 하는지를, 상투적인 거절처럼 들리지 않고 관계를 온전히 유지하는 방식으로 다룬다. 이 모든 것을 애초에 가능하게 만드는 그룹화와 라벨링 작업은 &lt;a href=&quot;https://changeloop.dev/blog/ko/feature-request-tracking/&quot;&gt;기능 요청 추적&lt;/a&gt;에서 다룬다. 우선순위 결정은 이미 기록되어 있고 비교할 수 있을 만큼 잘 그룹으로 묶인 요청에 대해서만 작동한다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;기능 요청 우선순위를 매기는 데 가장 좋은 프레임워크는 무엇인가?&lt;/strong&gt;
어느 것도 혼자서는 충분하지 않다. 가장 목소리 큰 신호를 찾기 위해 순수 요청 수를 쓰고, 진지한 후보 짧은 목록을 비교하기 위해 RICE를 쓰고, 전략적 계정의 조용한 수요가 더 목소리는 크지만 덜 중요한 그룹보다 무거운 경우를 잡아내기 위해 매출이나 계정 확인을 써라.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;기능 요청도 로드맵 아이디어와 같은 방식으로 우선순위를 매겨야 하는가?&lt;/strong&gt;
아니다. 로드맵 아이디어는 전략에서 시작하고, 기능 요청은 이미 존재하는 수요에서 시작한다. 둘을 함께 점수 매기면, 근거는 탄탄하지만 기존 수요가 적은 전략적 베팅이 그저 더 많은 사람이 요청했다는 이유만으로 계속 패배하게 된다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;공개 로드맵의 투표는 수요를 정확하게 반영하는가?&lt;/strong&gt;
이미 그 요청을 찾아낸 사람들 사이에서만 그렇다. 더 오래되고 더 눈에 띄는 요청은 더 새로운 요청 뒤에 얼마나 진짜 수요가 있는지와 무관하게 더 빨리 투표를 모으므로, 투표 합계를 순서대로 쌓아 올리는 순위표가 아니라 그룹으로 묶고 최신성으로 가중된 신호로 다뤄라.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;기능 요청 우선순위는 얼마나 자주 다시 평가해야 하는가?&lt;/strong&gt;
누군가 에스컬레이션할 때만이 아니라 고정된 주기로 하라. 요청을 다시 그룹으로 묶고 가중치를 다시 확인하는 월간 또는 분기별 검토는, 무엇이 출시되는지를 좌우하는 소수의 계정처럼 순수하게 반응적인 프로세스가 스스로는 결코 드러내지 못하는 편차를 잡아낸다.&lt;/p&gt;
</content:encoded></item><item><title>엔터프라이즈 릴리스 노트: 한 계정에 무엇이 달라지는가</title><link>https://changeloop.dev/blog/ko/private-release-notes-enterprise/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/private-release-notes-enterprise/</guid><description>엔터프라이즈 릴리스 노트는 비공개 빌드 위의 고객 인스턴스에 맞춰야 한다. 공개 블로그용을 그대로 보내면 고객이 혼란스러워지고 로드맵이 유출될 수 있다.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;공개 SaaS 제품은 모두에게 같은 릴리스 노트를 보낸다. 모두가 같은 버전에 있기 때문이다. 고정된
버전, 전용 인스턴스, 또는 기능 플래그가 적용된 제품의 하위 집합에 있는 엔터프라이즈 고객은 그
가정을 깨뜨린다. 그녀에게 무엇이 바뀌었는지 설명하는 릴리스 노트는 여러분의 공개 블로그에
있는 것과 같지 않으며, 어쨌든 공개용을 보내는 것은 아직 없는 변경 사항으로 고객을 혼란스럽게
하거나, 더 나쁘게는, 다른 엔터프라이즈 고객의 계정 팀이 한 달 더 자신들에게는 보류해 달라고
명시적으로 요청한 기능에 대해 그녀에게 알려주게 된다. &lt;a href=&quot;https://changeloop.dev/blog/ko/release-notes-best-practices/&quot;&gt;릴리스 노트 모범 사례&lt;/a&gt;는
일반적인 기술을 다룬다. 이 글은 고객이 모두 같은 빌드에 있지 않게 되면 나타나는 조정 문제를
위한 엔터프라이즈 릴리스 노트를 쓰는 것에 관한 것이다.&lt;/p&gt;
&lt;h2&gt;왜 엔터프라이즈 고객은 그냥 공개 체인지로그를 읽을 수 없는가&lt;/h2&gt;
&lt;p&gt;그것이 그녀가 아직 실행하지 않을지도 모르는 버전, 접근할 수 없을지도 모르는 기능, 그리고 그녀
자신의 것과 맞지 않는 일정을 설명하기 때문이다. 분기별 릴리스 주기에 고정된 고객이 지난주
공개 등급에 출시된 기능에 대해 읽는다면, 오직 공개 체인지로그만으로는 그 기능이 다음 주에
그녀에게 도달할지 다음 분기에 도달할지 알 방법이 없다. 공개 체인지로그는 &amp;quot;제품에서 무엇이
바뀌었는가&amp;quot;에 답한다. 엔터프라이즈 고객의 실제 질문은 &amp;quot;내가 실행 중인 버전에서 무엇이
바뀌었고, 나머지는 언제 받는가&amp;quot;이며, 공개 체인지로그는 그것에 답하기 위해 쓰인 적이 결코 없다.&lt;/p&gt;
&lt;h2&gt;비공개 릴리스 노트는 공개용이 필요하지 않은 무엇을 필요로 하는가&lt;/h2&gt;
&lt;p&gt;고객이 실제로 대조할 수 있는 버전 또는 환경 식별자와, 아직 그녀에게 도달하지 않은 것에 대한
명시적 진술이다. &amp;quot;이 릴리스에는 우리 공개 4.3 릴리스의 대량 내보내기 개선 사항이 포함되어
있지만, 여러분의 다음 예정된 업데이트에서 나올 새로운 권한 모델은 포함되어 있지 않습니다&amp;quot;는
엔터프라이즈 관리자에게 그녀의 인스턴스가 전체 제품에 비해 정확히 어디에 있는지 알려준다.
공개 릴리스 노트는 이런 틀을 결코 필요로 하지 않는데, 상대적으로 비교할 인스턴스가 하나뿐이기
때문이다. 비공개용은 그것 없이는 무의미하다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;공개 릴리스 노트&lt;/th&gt;
&lt;th&gt;비공개(엔터프라이즈) 릴리스 노트&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;하나의 버전, 하나의 청중&lt;/td&gt;
&lt;td&gt;여러 버전, 세분화된 청중&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;독자가 설명된 모든 기능을 가지고 있다고 가정함&lt;/td&gt;
&lt;td&gt;독자가 무엇을 가지고 있고 없는지 명시해야 함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;공개 릴리스에 맞춰 시기가 정해짐&lt;/td&gt;
&lt;td&gt;고객 자신의 업데이트 창에 맞춰 시기가 정해짐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;즉시 완전히 공개될 수 있음&lt;/td&gt;
&lt;td&gt;다른 고객이 아직 갖지 않은 항목을 보류해야 할 수 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;별도로 쓰는 대신 엔터프라이즈 고객에게 공개 릴리스 노트 발송을 그냥 미루는 것이 괜찮을 때가 있는가&lt;/h2&gt;
&lt;p&gt;그 순간 그녀의 버전이 정말로 공개용과 일치할 때만, 이는 리듬이 다른 엔터프라이즈 계정이 두어
개 이상 있게 되면 생각보다 드문 일이다. 공개 노트를 미루는 것은 한 버전 뒤처져 있고 곧 따라
잡으려는 고객에게 임시방편으로 작동한다. 그것은 두 엔터프라이즈 고객이 서로 다른 버전에 있는
순간 무너지는데, 그때는 미룰 단일한 &amp;quot;노트&amp;quot;가 더 이상 없고 각자가 무엇을 가졌는지의 행렬만
있기 때문이다. 그 시점에서, 같은 기본 항목들의 필터링된 보기에 불과하더라도, 계정별로 노트를
조정하는 것은 선택 사항이 아니게 된다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;아직 그 기능이 없는 엔터프라이즈 계정에 보낸
공개 노트:
&amp;quot;New: Bulk export now supports custom column ordering.&amp;quot;
(혼란: 관리자가 시도하지만 없다.)

같은 계정을 위해 조정된 엔터프라이즈 노트:
&amp;quot;Available in your next update (scheduled for 2026-10-15):
bulk export with custom column ordering. Not yet available
on your current version (3.8).&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;고객 조직 내에서 실제로 이것을 읽는 사람은 누구이며, 그것이 작성 방식을 바꾸는가&lt;/h2&gt;
&lt;p&gt;보통 최종 사용자가 아니라 IT 관리자나 customer success 담당자이며, 그것이 무엇을 유용하다고
여기는지를 바꾼다. 최종 사용자는 자신의 화면에서 무엇이 다르게 보이는지 알고 싶어한다.
엔터프라이즈 관리자는 권한, 데이터 처리, SSO 구성, 또는 자신의 사용자를 위해 배포를 어떻게
관리하는지에 영향을 미치는 무엇이든 무엇이 바뀌었는지 알고 싶어하는데, 내부 질문에 답할 사람이
바로 그녀이기 때문이다. 소비자용 체인지로그처럼 읽히는, 온통 반짝이는 새 버튼뿐이고 운영상의
세부 사항은 전혀 없는 비공개 릴리스 노트는 관리자가 정말로 필요했던 정보를 파헤치도록 강요한다.&lt;/p&gt;
&lt;h2&gt;이것이 이미 같은 기능을 나열하고 있는 공개 로드맵이나 공개 체인지로그와 어떻게 상호작용하는가&lt;/h2&gt;
&lt;p&gt;조심스럽게, 둘 다 읽는 고객은 어떤 불일치든 알아챌 것이기 때문이다. 여러분의 공개 체인지로그가
특정 엔터프라이즈 계정이 아직 갖지 않은 기능을 이미 공지했다면, 그 계정의 비공개 릴리스 노트는
공개 항목이 존재하지 않는 척하는 대신 그 격차를 인정해야 한다. 공개 발표를 보고 그것을
무시하는 비공개 노트를 받는 관리자는 여러분이 그녀를 잊었거나 무언가 고장 났다고 추측할
것이다. &lt;a href=&quot;https://changeloop.dev/blog/ko/public-roadmap/&quot;&gt;공개 로드맵&lt;/a&gt;은 무엇이 출시되었는지 대 무엇이 계획되었는지에
대해 로드맵을 정직하게 유지하는 방법을 다룬다. 릴리스 노트에서 그 정직함의 엔터프라이즈
버전은 공개된 것과 그녀의 것 사이의 격차를 직접 명명하는 것이다.&lt;/p&gt;
&lt;h2&gt;엔터프라이즈 고객이 한둘뿐인 작은 회사도 이만큼의 구조가 필요한가&lt;/h2&gt;
&lt;p&gt;완전히 세분화된 시스템은 아니지만, 고객이 어떤 버전에 있고 무엇을 가지고 있고 없는지를 명확히
진술하는 핵심 규율은 여러분의 최신 빌드에 있지 않은 고객이 단 한 명이라도 있는 순간부터 어떤
규모에서든 중요하다. 이것이 막는 실패 모드, 공개 발표가 자신에게 적용되는지 혼란스러워하는
관리자는, 엔터프라이즈 계정이 두 개든 이백 개든 상관없이 지원 티켓과 신뢰에 대한 타격이라는
비용을 치르게 한다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;비공개 릴리스 노트는 다른 고객이 이미 가지고 있지만 이 고객은 없는 기능을 언급해야 하는가?&lt;/strong&gt;
그녀 자신의 일정에 관련이 있을 때만, 다른 고객과의 비교가 아니라 &amp;quot;다음 업데이트에서 나옵니다&amp;quot;로
표현되어야 한다. 특정 다른 고객이 무엇을 가지고 있는지 명명하는 것은 여러분이 공개할 권리가
없는 영역을 넘어간다. 이 고객에게 구체적으로 무엇이 올지 명명하는 것은 정확히 그녀가 필요로
하는 정보다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;같은 기본 체인지로그 항목들이 공개와 비공개 릴리스 노트 모두를 지원할 수 있는가?&lt;/strong&gt;
그렇다, 그리고 그것이 보통 더 유지 관리하기 쉬운 접근법이다. 항목에 어떤 버전이나 등급에
적용되는지 태그를 붙이고, 필연적으로 서로 어긋나게 될 완전히 별개의 두 문서를 쓰는 대신 발행
시점에 청중별로 필터링하라.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;엔터프라이즈 고객이 비공개 피드 대신 공개 릴리스 노트에 있기를 명시적으로 요청하면 어떻게 하는가?&lt;/strong&gt;
그것을 존중하되, 공개 노트가 공개 버전을 가정한다는 것을 그녀가 이해하는지 확인하고, 그녀의
버전이 설명과 다르다면 여러분 스스로 서면으로 그 격차를 표시하라. 그 서면 확인이 나중에 그녀가
실제로는 자신의 빌드에 적용되지 않는 공개 노트에 따라 행동할 경우 여러분을 보호해준다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;엔터프라이즈 고객은 다음 릴리스에서 접근하게 될 기능에 대해 얼마나 미리 알림을 받아야 하는가?&lt;/strong&gt;
릴리스 시점뿐만이 아니라 날짜가 확정되는 즉시. 엔터프라이즈 관리자는 다가오는 기능을 둘러싸고
자신의 내부 소통이나 교육을 계획해야 하는 경우가 많은데, 당일 알림은 그럴 여지를 그녀에게
남기지 않기 때문이다.&lt;/p&gt;
</content:encoded></item><item><title>시맨틱 버저닝과 당신의 체인지로그, 함께 보기</title><link>https://changeloop.dev/blog/ko/semantic-versioning-changelog/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/semantic-versioning-changelog/</guid><description>시맨틱 버저닝은 호출자가 체인지로그 항목을 읽기 전에 릴리스가 얼마나 아플지 알려준다. 각 숫자가 약속하는 것과 항목이 그에 대해 져야 할 책임을 설명한다.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;시맨틱 버저닝은 호출자가 체인지로그 항목을 하나도 읽기 전에 릴리스가 얼마나 아플 수 있는지 알려준다. &lt;code&gt;2.4.1&lt;/code&gt;에서 &lt;code&gt;2.5.0&lt;/code&gt;으로 가는 것은 이렇게 말한다. 새로운 기능, 아무것도 깨지지 않는다. &lt;code&gt;2.5.0&lt;/code&gt;에서 &lt;code&gt;3.0.0&lt;/code&gt;으로 가는 것은 이렇게 말한다. 업데이트 전에 이 항목을 읽어라. 체인지로그와 버전 번호는 두 형식으로 같은 것을 주장해야 하며, 둘 사이의 마찰 대부분은 정확히 둘이 일치하지 않을 때 나타나는데, 이는 명세가 시사하는 것보다 더 자주 일어난다.&lt;/p&gt;
&lt;h2&gt;버전의 각 숫자는 실제로 무엇을 약속하는가&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://semver.org/&quot;&gt;시맨틱 버저닝&lt;/a&gt;은 세 숫자를 정의한다. &lt;code&gt;MAJOR.MINOR.PATCH&lt;/code&gt;, 각각 무엇이 그것을 트리거하는지에 대한 엄격한 규칙이 있다. MAJOR 상승은 호환되지 않는 변경을 의미한다. 올바르게 작성된 기존 통합이 알아챌 수 있고 그 때문에 바뀌어야 하는 무언가다. MINOR 상승은 새롭고 하위 호환되는 기능을 의미한다. 기존의 어떤 것도 깨지지 않고, 새로운 것이 사용 가능해진다. PATCH 상승은 하위 호환되는 수정을 의미한다. 동작이 문서화된 것에 더 가까워지고, 의도적으로 이전 동작에 의존한 사람이라면 아무것도 알아채지 못해야 한다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;상승&lt;/th&gt;
&lt;th&gt;의미&lt;/th&gt;
&lt;th&gt;항목은 이렇게 읽혀야 한다&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;MAJOR (&lt;code&gt;1.x.x&lt;/code&gt; -&amp;gt; &lt;code&gt;2.0.0&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;호환되지 않는 변경&lt;/td&gt;
&lt;td&gt;&amp;quot;업데이트 전에 조치가 필요하다&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MINOR (&lt;code&gt;1.2.x&lt;/code&gt; -&amp;gt; &lt;code&gt;1.3.0&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;새롭고 호환되는 기능&lt;/td&gt;
&lt;td&gt;&amp;quot;지금부터 사용 가능, 다른 건 안 바뀜&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PATCH (&lt;code&gt;1.2.3&lt;/code&gt; -&amp;gt; &lt;code&gt;1.2.4&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;호환되는 수정&lt;/td&gt;
&lt;td&gt;&amp;quot;이제 문서화된 대로 동작한다&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;이 표는 거꾸로도 테스트가 된다. 항목이 자기 행처럼 읽히지 않는다면, 버전 번호가 틀렸거나 항목이 실제로 일어난 일을 과소평가하거나 과대평가하는 것이다.&lt;/p&gt;
&lt;h2&gt;버전 관리 목적으로 무엇이 호환되지 않는 것으로 간주되는가&lt;/h2&gt;
&lt;p&gt;무언가가 API 체인지로그에 속하는지를 결정하는 것과 같은 테스트다. 이전 동작에 맞춰 작성되고 그 이후 손대지 않은 올바른 호출자가 이 변경 때문에 다르게 동작할 수 있는가. &lt;a href=&quot;https://changeloop.dev/blog/ko/breaking-changes/&quot;&gt;호환되지 않는 변경이란 무엇이고 어떻게 출시하는가&lt;/a&gt;가 그 판단을 완전히 다루며, 호환되지 않아 보이지만 아닌 경우와 작아 보이지만 아닌 경우도 포함한다. 버전 관리 목적으로 짧게 말하면, 답이 그렇다면, 변경이 내부적으로 실제로 얼마나 많은 코드를 건드렸는지와 상관없이 상승은 MAJOR다. 버전 번호는 팀의 노력이 아니라 호출자에게 미치는 결과를 추적한다.&lt;/p&gt;
&lt;h2&gt;체인지로그 항목은 버전 상승과 어떻게 맞아야 하는가&lt;/h2&gt;
&lt;p&gt;하나의 항목, 하나의 상승 카테고리를, 맨 앞에서 밝힌다. 표의 패턴이 그대로 이어진다. 호환되지 않는 항목은 그것을 도입한 버전 아래에 놓이며, 먼저 경고로, 그다음 설명으로 표현된다. 추가적인 항목은 자신의 MINOR 버전 아래에 놓이며, 사용 가능성으로 표현된다. 수정은 자신의 PATCH 버전 아래에 놓이며, 정정으로 표현된다. 하나의 항목에서 카테고리를 섞는 것, 예를 들어 호환되지 않는 변경을 무관한 수정과 같은 단락에 접어 넣는 것은 독자가 정말로 중요했던 그 한 가지를 놓치게 만드는 방식이다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;## 3.0.0 (2026-09-07)

### Changed
- **BREAKING:** `GET /reports`가 이제 금액을 소수점 대신 최소 통화 단
  위(센트)의 정수로 반환한다. `amount`를 직접 읽는 코드를 업데이트하라
  .

## 2.9.0 (2026-09-01)

### Added
- 보고서를 이제 `status`로 필터링할 수 있다.

## 2.8.4 (2026-08-28)

### Fixed
- `GET /reports?status=`가 알 수 없는 상태에 대해 400 대신 빈 페이지를
   반환했다.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위에서 아래로 읽으면 버전 번호와 섹션 라벨이 같은 것을 두 번 말한다. 바로 그것이 목적이다. 제목만 훑어보는 독자도 한 줄도 열지 않고 올바른 위험 판단을 얻는다.&lt;/p&gt;
&lt;h2&gt;파괴적 변경 규칙은 1.0.0 이전에도 똑같이 적용되는가&lt;/h2&gt;
&lt;p&gt;아니다, 그리고 &amp;quot;그게 정말 파괴적이었나&amp;quot;를 둘러싼 대부분의 혼란이 여기서 나온다. SemVer는 메이저 버전 0, 즉 &lt;code&gt;0.y.z&lt;/code&gt;가 초기 개발용이라고 명시한다. 언제든 무엇이든 바뀔 수 있고, 공개 API는 안정적이라고 여겨져서는 안 된다. &lt;code&gt;0.4.0&lt;/code&gt;에서 &lt;code&gt;0.5.0&lt;/code&gt;으로의 상승은 스펙을 어기지 않고도 파괴적 변경을 담을 수 있다. 메이저 버전 보장은 프로젝트가 &lt;code&gt;1.0.0&lt;/code&gt;을 출시한 이후에야 시작되기 때문이다. 체인지로그 항목은 무엇이 깨졌는지에 대해 여전히 독자에게 같은 정직함을 빚지고 있다. 달라지는 것은 오직, 1.0.0에 이르기 전까지는 버전 번호 자체가 믿을 만한 신호가 아니라는 점뿐이다.&lt;/p&gt;
&lt;h2&gt;제품이 개별 버전을 출시하지 않는다면 어떤가&lt;/h2&gt;
&lt;p&gt;대부분의 SaaS 제품은 지속적으로 배포되며 호출자에게 버전 번호를 절대 보여주지 않는데, 이것이 이 원칙의 필요성을 없애지는 않고, 그것을 보통 담아냈을 숫자만 없앤다. 체인지로그 항목이 모든 일을 혼자 해야 한다. 변경이 호환되지 않는지, 추가적인지, 수정인지를, 시맨틱 버저닝이 쓰는 것과 같은 세 단어로, 그것을 붙일 버전 필드가 없어도 명확히 말해야 한다. 일부 팀은 체인지로그 항목을 링크할 수 있는 무언가에 고정하기 위해서만, 호출자에게 직접 보여주지 않고 순전히 내부용 버전을 유지한다.&lt;/p&gt;
&lt;h2&gt;이것이 API 체인지로그에는 구체적으로 어떻게 적용되는가&lt;/h2&gt;
&lt;p&gt;거의 다른 어디보다 더 엄격하게, API의 호출자는 예상치 못한 변경에 어깨를 으쓱할 수 있는 사람이 아니라 코드이기 때문이다. &lt;a href=&quot;https://changeloop.dev/blog/ko/api-changelog/&quot;&gt;API 체인지로그: 무엇을 공개하고 누가 읽는가&lt;/a&gt;가 그 문서의 완전한 형태를 다룬다. 여기서의 버전 관리 원칙은 그것의 breaking 섹션과 additive 섹션을 정직하게 유지하는 것이다. 마이그레이션 기간 동안 &lt;code&gt;v1&lt;/code&gt;과 &lt;code&gt;v2&lt;/code&gt;를 나란히 제공하는 것처럼 여러 버전을 동시에 제공하는 API는 사실상 하나의 패키지가 아니라 전체 인터페이스 규모에서 시맨틱 버저닝을 적용하고 있는 것이며, 같은 세 단어 어휘가 여전히 모든 항목에 적용된다.&lt;/p&gt;
&lt;h2&gt;Keep a Changelog는 버전 관리에 대해 무엇을 말하는가&lt;/h2&gt;
&lt;p&gt;이름으로 시맨틱 버저닝과 직접 연결되며, 이 글이 쓰는 것과 같은 카테고리 어휘를 권장한다. Added, Changed, Deprecated, Removed, Fixed, Security. &lt;a href=&quot;https://changeloop.dev/blog/ko/keep-a-changelog-implemented/&quot;&gt;Keep a Changelog, 실전편&lt;/a&gt;이 그 명세를 채택하는 방법을, 팀이 거기서 벗어나는 지점까지 포함해서 다룬다. 이 겹침은 우연이 아니다. 두 명세 모두 반대편 끝에서 같은 문제를 풀려고 하는 것이다. 하나는 버전 번호를 표준화하고 다른 하나는 그것을 설명하는 항목을 표준화한다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;모든 체인지로그 항목에 버전 번호가 필요한가?&lt;/strong&gt;
제품이 버전을 출시한다면 그렇다. 숫자가 독자로 하여금 항목을 먼저 읽지 않고도 &amp;quot;이것이 나에게 얼마나 영향을 미치는가&amp;quot;로 바로 넘어갈 수 있게 해주기 때문이다. 제품이 버전 필드 없이 지속적으로 배포된다면, 항목의 표현이 그 신호를 혼자 담아야 한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;MAJOR 상승과 호환되지 않는 변경 항목의 차이는 무엇인가?&lt;/strong&gt;
둘은 같은 사건을 두 방식으로 설명해야 한다. 버전 번호는 기계가 읽는 신호이고(호출자의 도구가 그것에 반응할 수 있다), 체인지로그 항목은 구체적으로 무엇이 바뀌었는지에 대한 사람이 읽는 설명이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PATCH 릴리스가 호환되지 않을 수 있는가?&lt;/strong&gt;
정의상 그러면 안 된다. 그래도 출시되었다면, 발행된 버전을 수정하거나 태그를 다시 붙이지 마라. &lt;a href=&quot;https://semver.org/#what-do-i-do-if-i-accidentally-release-a-backward-incompatible-change-as-a-minor-version&quot;&gt;SemVer FAQ&lt;/a&gt;는 호환성을 복원하는 새 버전을 릴리스하거나, 호환되지 않는 변경을 유지한다면 새 MAJOR를 릴리스하고, 문제가 된 버전을 문서화해 사용자가 그것을 건너뛸 수 있게 하라고 말한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;순전히 내부적인 변경에도 버전 상승이 필요한가?&lt;/strong&gt;
아니다. 시맨틱 버저닝은 공개 인터페이스를 추적한다. 호출자에게 관찰 가능한 영향이 없는 리팩터링은 내부적으로 상당한 엔지니어링 작업이었더라도 상승도 체인지로그 항목도 필요 없다.&lt;/p&gt;
</content:encoded></item><item><title>웹훅 체인지로그, 아무도 요청하지 않은 파괴적 변경</title><link>https://changeloop.dev/blog/ko/webhook-changelog/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/webhook-changelog/</guid><description>웹훅 페이로드 변경은 새 형태를 거부할 호출자가 없어 조용히 깨진다. 무엇이 파괴적 변경인지와 버전을 매기는 방법을 다룬다.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;REST API 체인지로그가 존재하는 이유는 호출자가 이해하지 못하는 응답을 거부할 수 있거나, 적어도 누군가 알아챌 만큼 시끄럽게 오류를 로그로 남길 수 있기 때문이다. 웹훅 수신자는 그 둘 중 어느 것도 거의 하지 못한다. POST를 받고, 기대하는 필드를 읽으며, 어떤 필드가 이동했거나 타입이 바뀌었거나 사라졌다면, 엔드포인트는 아무도 지켜보지 않는 백그라운드 작업 안에서 조용히 죽거나, 더 나쁘게는 한 번도 검증한 적 없는 잘못된 값으로 계속 돌아간다. &lt;a href=&quot;https://changeloop.dev/blog/ko/breaking-changes/&quot;&gt;파괴적 변경이란 무엇인가&lt;/a&gt;는 일반적인 정의를 다룬다. 웹훅 페이로드는 자기만의 답이 필요하다. 누군가 의도적으로 호출하는 엔드포인트와는 실패하는 방식이 다르기 때문이다.&lt;/p&gt;
&lt;h2&gt;웹훅 페이로드 변경은 왜 API 응답 변경과 다르게 깨지는가&lt;/h2&gt;
&lt;p&gt;요청의 방향이 뒤집혀 있기 때문이다. REST 호출자는 호출을 시작하며 버전 헤더를 추가하거나, 4xx에서 재시도하거나, 응답 속 사용 중단 알림을 읽을 수 있다. 웹훅 수신자는 그 중 어느 것도 시작하지 않았다. 여러분의 서버가 보내기로 결정했고, 언제 보낼지 결정했고, 본문이 어떤 형태를 가질지 결정했다. 수신자의 유일한 지렛대는 통합을 구축할 때 작성한 검증이며, 대부분의 통합은 한 번 구축되고 작동한 뒤 깨질 때까지 아무도 다시 들여다보지 않는다. 이 비대칭이 웹훅 페이로드 변경이 호출자가 능동적으로 요청한 응답 본문의 동일한 변경보다 더 많은 주의를 받을 가치가 있는 모든 이유다.&lt;/p&gt;
&lt;h2&gt;웹훅 페이로드에서 실제로 파괴적 변경으로 간주되는 것은 무엇인가&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;변경&lt;/th&gt;
&lt;th&gt;대부분의 수신자에게 파괴적인가&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;새 필드 추가&lt;/td&gt;
&lt;td&gt;수신자가 알 수 없는 필드를 무시한다면 아니오 (이 가정을 검증하라, 당연시하지 말라)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;필드 제거&lt;/td&gt;
&lt;td&gt;무언가 그것을 읽는다면 예&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;필드 이름 변경&lt;/td&gt;
&lt;td&gt;기존 것을 제거하는 것과 기능적으로 동일하므로 예&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;필드 타입 변경 (문자열에서 객체로)&lt;/td&gt;
&lt;td&gt;거의 항상 예&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JSON 본문의 필드 순서 변경&lt;/td&gt;
&lt;td&gt;키로 파싱하는 모든 수신자에게 아니오 (모두가 그래야 한다)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;이벤트 이름이나 타입 변경&lt;/td&gt;
&lt;td&gt;수신자가 그것으로 필터링하거나 라우팅한다면 예&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&amp;quot;필드를 추가하는 것은 안전하다&amp;quot;라는 줄은 팀들이 가장 많이 의존하는 줄이자 당연시하는 대신 검증할 가치가 가장 큰 줄이다. 관대한 JSON 파서는 기본적으로 알 수 없는 필드를 무시하지만, 엄격한 스키마로 역직렬화하는 수신자, 몇몇 타입 언어는 추가 설정 없이 이렇게 한다, 는 예상치 못한 필드가 나타나는 순간 전체 페이로드를 거부할 수 있다. 필드 추가가 여러분의 웹훅에 안전한 것은 오직 수신자들이 어떻게 파싱하는지 알고 있을 때뿐이며, JSON 자체가 관대해서가 아니다.&lt;/p&gt;
&lt;h2&gt;웹훅 페이로드는 어떻게 버전을 매겨야 하는가&lt;/h2&gt;
&lt;p&gt;API 응답의 경우와 거의 같지만 한 가지 차이가 있다. 수신자는 요청을 보내지 않으므로 버전을 요구할 수 없고, 송신자가 그것을 명시해야 한다. 그것은 본문에 넣을 수도 있고 전달 자체의 요청 헤더에 넣을 수도 있다. &lt;a href=&quot;https://docs.github.com/en/webhooks/webhook-events-and-payloads&quot;&gt;GitHub의 전달&lt;/a&gt;은 &lt;code&gt;X-GitHub-Event&lt;/code&gt;와 &lt;code&gt;X-GitHub-Hook-ID&lt;/code&gt;를 담고, &lt;a href=&quot;https://github.com/standard-webhooks/standard-webhooks/blob/main/spec/standard-webhooks.md&quot;&gt;Standard Webhooks 명세&lt;/a&gt;는 메타데이터를 &lt;code&gt;webhook-*&lt;/code&gt; 헤더에 넣는다. 페이로드 안의 버전 필드(&lt;code&gt;&amp;quot;payload_version&amp;quot;: 2&lt;/code&gt;)는 가장 저렴한 선택지이며 수신자들이 그것에 따라 분기할 의향이 있을 때 작동한다. 버전이 매겨진 이벤트 타입(&lt;code&gt;invoice.updated&lt;/code&gt;가 수신자가 자발적으로 구독하는 별개의 이벤트로서 &lt;code&gt;invoice.updated.v2&lt;/code&gt;가 되는 것)은 구축하는 데 더 많은 작업이 필요하지만, 한 번도 이전하지 않은 이들에게 기존 형태가 계속 흘러간다는 것을 의미하며, 이는 REST 엔드포인트보다 여기서 더 중요하다. 모든 수신자에게 전화해 업데이트하라고 요청할 수는 없기 때문이다. 웹훅 엔드포인트를 등록할 때 선택하는 구독별 설정은 매 전달마다 분기하는 대신 결정을 미리 내려두며, 이미 붙일 구독 기록을 가지고 있을 때 올바른 선택이다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;POST /receiver-endpoint
{
  &amp;quot;event&amp;quot;: &amp;quot;invoice.updated&amp;quot;,
  &amp;quot;payload_version&amp;quot;: 2,
  &amp;quot;data&amp;quot;: { &amp;quot;invoice_id&amp;quot;: &amp;quot;inv_123&amp;quot;, &amp;quot;status&amp;quot;: &amp;quot;paid&amp;quot; }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;애초에 누가 듣고 있는지 어떻게 아는가&lt;/h2&gt;
&lt;p&gt;API 체인지로그에서 이 문제의 동등한 버전보다 나쁘다. 웹훅은 호출자를 이름 짓는, 여러분 쪽의 수신 요청 로그를 가지고 있지 않기 때문이다. 여러분에게는 엔드포인트가 200을 받았다는 것만 말해주는 자신의 송신 전달 로그만 있을 뿐, 본문으로 무엇을 했는지는 알 수 없다. 최소한 두 가지를 추적하라. &lt;a href=&quot;https://changeloop.dev/blog/ko/internal-api-changelog/&quot;&gt;내부 API 체인지로그&lt;/a&gt;가 내부 소비자에게 권장하는 것과 같은 규율로, 소유자가 있는 모든 등록된 엔드포인트와, 페이로드 변경 후 엔드포인트별 전달 실패율이다. 변경 직후 한 엔드포인트에서 오는 4xx나 5xx 응답의 급증은 여러분이 얻을 수 있는 스택 트레이스에 가장 가까운 것이며, 종종 수신자가 깨졌다는 유일한 신호다. 그것을 운영하는 팀이 며칠 동안 알아채지 못할 수 있기 때문이다.&lt;/p&gt;
&lt;h2&gt;웹훅 체인지로그는 API 체인지로그와 분리되어야 하는가&lt;/h2&gt;
&lt;p&gt;같은 페이지의 별도 섹션이지, 별도의 발행물이 아니다. &lt;a href=&quot;https://changeloop.dev/blog/ko/api-changelog/&quot;&gt;API 체인지로그&lt;/a&gt;는 이미 누가 그것을 읽고 어떻게 구독하는지를 정립한다. 웹훅 페이로드 변경은 같은 피드에 속하며, &amp;quot;이것이 내 통합에 영향을 미치는가&amp;quot;를 훑어보는 수신자 측 개발자가 필터링할 수 있을 만큼 충분히 명확하게 라벨이 붙어야 한다. 웹훅 소비자는 일반적인 API 체인지로그를 확인할 다른 이유가 거의 없으며, 누군가 그곳으로 직접 안내해야만 찾게 되기 때문이다.&lt;/p&gt;
&lt;h2&gt;웹훅 페이로드에 대한 합리적인 사용 중단 기간은 어떤 모습이어야 하는가&lt;/h2&gt;
&lt;p&gt;동등한 REST 사용 중단보다 길어야 한다. 수신자 측 이전은 보통 여러분이 직접적인 연락 수단이 없을지도 모르는 두 번째 팀이 그것을 알아채고, 계획하고, 자체 긴급성 없이 배포해야 함을 의미하기 때문이다. 수신자가 여전히 관대한 라이브러리로 파싱하고 있을 가능성이 높은 필드에는 한 달이 합리적인 최소치다. 엄격한 스키마라면 완전히 거부할 필드 제거에는 세 달 이상이 더 안전하다. 가능하다면 기간 동안 기존 형태와 새 형태를 함께 보내라(기존 &lt;code&gt;status&lt;/code&gt; 필드와 그 버전 2 대체 필드가 같은 페이로드에 함께 들어가도록). 기존 필드를 읽는 수신자는 코드를 건드리지 않고도 계속 작동하고, 이미 이전한 수신자는 더 이상 필요 없는 필드를 그냥 무시하기 때문이다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;웹훅 소비자는 페이로드 변경이 공개되기 전에 확인해야 하는가?&lt;/strong&gt;
기본적으로 확인 메커니즘은 존재하지 않으며, 바로 그 때문에 사용 중단 기간이 REST API보다 여기서 더 중요하다. 아무도 준비되었다고 확인하지 않으므로, 기존 형태가 사라지기 전에 대부분의 수신자가 자기 속도로 이전할 수 있을 만큼 기간이 길어야 한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;알 수 없는 필드를 통보 없이 추가하는 것이 안전한 경우가 있는가?&lt;/strong&gt;
수신자들이 관대하게 파싱한다는 것을 당연시하지 않고 검증한 후에만 그렇다. 체인지로그 항목 하나는 비용이 거의 들지 않고 추측을 없앤다. &amp;quot;JSON 파서는 여분을 무시한다&amp;quot;는 가정으로 조용히 필드를 추가하면 엄격한 역직렬화를 사용하는 모든 수신자가 깨진다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;페이로드 변경 후 깨진 웹훅 수신자를 감지하는 가장 빠른 방법은 무엇인가?&lt;/strong&gt;
변경 직후 몇 시간 동안 관찰되는 엔드포인트별 전달 실패율이다. 무엇이 깨졌는지는 말해주지 않고 무언가 깨졌다는 것만 말해주지만, 여러분이 얻을 수 있는 가장 이른, 그리고 종종 유일한 신호다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;재시도 로직이 수신자가 페이로드 변경을 견디는 데 도움이 되는가?&lt;/strong&gt;
아니다. 재시도는 같은 새 페이로드를 다시 보낼 뿐, 수신자가 파싱할 수 있는 형태로 돌아가지 않는다. 페이로드 변경은 첫 전달에서도, 이후 모든 재시도에서도 수신자를 동일하게 깨뜨린다.&lt;/p&gt;
</content:encoded></item><item><title>API Sunset 헤더, 언제 보내야 하는가</title><link>https://changeloop.dev/blog/ko/sunsetting-api-version/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/sunsetting-api-version/</guid><description>API Sunset 헤더는 비추천 공지와 달리 클라이언트에 버전이 응답을 멈춘다고 알린다. RFC 8594가 다루는 범위와 브라운아웃의 이점을 설명한다.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;code&gt;Sunset&lt;/code&gt;은 &lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc8594&quot;&gt;RFC 8594&lt;/a&gt;에 정의된 단일 응답 헤더로, 어떤
리소스가 언제 응답을 멈출지를 호출자에게 알려준다. &lt;a href=&quot;https://changeloop.dev/blog/ko/api-deprecation/&quot;&gt;API 비추천 처리&lt;/a&gt;
는 공지-재알림-브라운아웃-폐기로 이어지는 전체 타임라인과 그에 따른 통지들을 다룬다. 이 글은
그 타임라인 안에서 유일하게 기계가 읽을 수 있는 신호인 이 헤더에 관한 것으로, 그것이 실제로
무엇을 말하는지, 그리고 RFC 자체가 보내지 말라고 말하는 유일한 경우에 관한 것이다.&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;Sunset&lt;/code&gt; 헤더는 무엇을 말하고, 무엇을 말하지 않는가&lt;/h2&gt;
&lt;p&gt;이 헤더는 단일 HTTP 날짜, 즉 그 리소스가 응답하지 않게 될 것으로 예상되는 시점을 담는다:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Sunset: Sat, 31 Dec 2028 23:59:59 GMT
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;RFC는 이를 보장이 아니라 힌트라고 부른다. 그 시점까지 리소스가 계속 작동한다는 것을 약속하지
않으며, 이후 실패가 어떤 모습일지에 대해서도 아무 말이 없다. 호출자는 4xx를 받을 수도, 리다
이렉트될 수도, 아예 응답을 받지 못할 수도 있다. 헤더는 이를 구분하지 않는다. 이미 과거인 타임
스탬프는 값의 오류가 아니라 &amp;quot;지금, 혹은 언제든지&amp;quot;를 의미한다. 이 중 어느 것도 프로토콜에 의해
강제되지 않는다. 헤더를 전혀 읽지 않는 클라이언트는 늘 그래왔던 것과 똑같이 동작하며, 리소스
가 사라졌다는 사실을 어차피 알게 됐을 방식 그대로 알게 된다.&lt;/p&gt;
&lt;h2&gt;실제로 언제 보내야 하는가&lt;/h2&gt;
&lt;p&gt;리소스가 정말로 응답을 멈추게 될 때만 보내야 하며, 단지 더 이상 권장되는 선택지가 아닌 단계
에서는 보내지 않는다. RFC는 비추천 처리가 두 단계로 일어난다는 점을 명시하며, &lt;code&gt;Sunset&lt;/code&gt; 헤더
필드는 그중 두 번째 단계에만 속한다. 첫 번째 단계, 즉 어떤 버전이 더 이상 선호되지 않는다는
공지 단계에서는 API가 완전히 정상 작동하며, 이 헤더 필드는 그 단계에 적용되지 않는다. 버전이
실제로 응답을 멈추도록 예정된 시점이 되어야 적용된다.&lt;/p&gt;
&lt;p&gt;이는 비추천 처리 타임라인과 정확히 맞물린다. &lt;code&gt;Deprecation&lt;/code&gt; 헤더는 공지 단계인 첫날부터 나가
고, &lt;code&gt;Sunset&lt;/code&gt;은 기존 동작이 실제로 멈추는 날짜를 나타내는데, 이는 &lt;a href=&quot;https://changeloop.dev/blog/ko/api-deprecation/&quot;&gt;4단계 타임라인&lt;/a&gt;
이 폐기라고 부르는 것과 같은 날짜다. 첫날에 &lt;code&gt;Sunset&lt;/code&gt;을 보내는 것 자체는 틀리지 않다. 그 시점
에 날짜가 이미 확정되어 있다면 말이다. 하지만 비추천 처리를 공지하지도 않은 채 보내거나, 실제
로는 폐기를 확정하지 않은 버전에 설정해 버리면, 아직 결정하지도 않은 것을 호출자에게 말해
버리는 셈이 된다.&lt;/p&gt;
&lt;h2&gt;이것은 캐싱과 상호작용하는가&lt;/h2&gt;
&lt;p&gt;아니다. RFC는 이를 명확히 밝히고 있다. &lt;code&gt;Sunset&lt;/code&gt;과 HTTP 캐싱은 서로 무관한 문제를 해결하며,
겹치는 것이 아니라 서로 보완하는 것으로 읽어야 한다. 캐싱 헤더는 캐시된 사본을 언제 재사용해도
안전한지를 말해준다. &lt;code&gt;Sunset&lt;/code&gt;은 리소스의 현재 상태에 대해서는 아무 말도 하지 않으며, 오직 그
리소스 자체가 언젠가 존재하지 않게 될 것이라는 점만을 말한다. 응답은 실제로 종료를 맞이하는
순간 직전까지도 완전히 캐시 가능할 수 있다. 하나로 다른 하나를 근사하려 하지 말고, 긴 &lt;code&gt;max-age&lt;/code&gt;
가 다가오는 종료일을 상쇄한다거나 그 반대라고 가정하지도 말라.&lt;/p&gt;
&lt;h2&gt;하나의 헤더로 여러 엔드포인트를 종료시킬 수 있는가&lt;/h2&gt;
&lt;p&gt;헤더는 그것을 반환한 리소스에 적용되지만, RFC는 서비스가 더 넓은 범위를 문서화하는 것을
허용한다. API의 홈 리소스에 설정된 종료 날짜를 그 URL 하나만이 아니라 API 전체가 사라진다는
의미로 정의할 수 있다. 다만 이는 그 스코프 규칙을 이미 알고 있는 호출자에게만 통한다는 함정이
있다. 헤더를 액면 그대로 읽는 호출자에게는 자신이 요청한 리소스 하나에 대한 종료만 보이고
그 외에는 아무것도 보이지 않는다. 따라서 더 넓은 범위는 암묵적으로 남겨둘 것이 아니라 호출자
가 찾을 수 있는 어딘가에 명시해 두어야 한다.&lt;/p&gt;
&lt;h2&gt;헤더와 함께 무엇을 실어야 하는가&lt;/h2&gt;
&lt;p&gt;폐기에 대해 설명하는 곳으로 가는 링크다. RFC 8594는 정확히 이를 위해 자체 &lt;code&gt;sunset&lt;/code&gt; 링크 관계
를 등록해 두었다. 폐기 정책, 다가오는 날짜, 또는 마이그레이션 방법을 설명하는 리소스를 가리
키기 위한 것으로, 헤더의 단순한 타임스탬프와는 별개다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP/1.1 200 OK
Sunset: Sat, 31 Dec 2028 23:59:59 GMT
Link: &amp;lt;https://example.com/docs/sunset-policy&amp;gt;; rel=&amp;quot;sunset&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그 링크를 자체 &lt;a href=&quot;https://changeloop.dev/changelog-examples&quot;&gt;체인지로그 예시&lt;/a&gt;나 전용 마이그레이션 페이지로 향하게
하면, 거의 아무도의 클라이언트 코드도 검사하지 않는 헤더가 실제로 찾아보는 사람이 즉시 발견
할 수 있는 것으로 바뀐다. &lt;a href=&quot;https://changeloop.dev/blog/ko/api-deprecation/#which-headers-should-a-deprecated-endpoint-send&quot;&gt;비추천 처리 헤더&lt;/a&gt;
의 &lt;code&gt;successor-version&lt;/code&gt; 관계와 결합하면, 호출자는 응답만으로 어디로 가야 하는지와 무엇이 이를
대체하는지를 모두 얻는다.&lt;/p&gt;
&lt;h2&gt;이것은 처음부터 끝까지 어떤 모습인가&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;v1&lt;/code&gt;이 2027년 3월 1일에 사라진다고 하자. 첫날의 비추천 처리 공지는 &lt;a href=&quot;https://changeloop.dev/blog/ko/api-deprecation/&quot;&gt;비추천 처리 헤더&lt;/a&gt;
에 따라 모든 &lt;code&gt;v1&lt;/code&gt; 응답에 &lt;code&gt;Deprecation&lt;/code&gt;과 &lt;code&gt;Link: rel=&amp;quot;successor-version&amp;quot;&lt;/code&gt;을 추가하지만, 폐기
날짜가 임시값이 아니라 정말로 확정될 때까지는 &lt;code&gt;Sunset&lt;/code&gt;을 보류한다. 확정되고 나면, 모든 &lt;code&gt;v1&lt;/code&gt;
응답은 다음을 싣는다:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP/1.1 200 OK
Deprecation: @1756425600
Sunset: Mon, 01 Mar 2027 00:00:00 GMT
Link: &amp;lt;https://api.example.com/v2/reports&amp;gt;; rel=&amp;quot;successor-version&amp;quot;
Link: &amp;lt;https://example.com/docs/sunset-policy&amp;gt;; rel=&amp;quot;sunset&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;호출자의 게이트웨이나 모니터링은 두 헤더 각각에 독립적으로 경보를 걸 수 있다. &lt;code&gt;Deprecation&lt;/code&gt;
은 더 새로운 버전이 존재한다는 것을, &lt;code&gt;Sunset&lt;/code&gt;은 이 버전에 시계가 걸려 있다는 것을 말한다.
3월 1일 이전에 두 헤더 중 어느 것도 바뀔 필요는 없다. 바뀌는 것은 응답 그 자체이며, 그것도
당일과 그 전에 예정된 브라운아웃 기간 동안 일어난다.&lt;/p&gt;
&lt;h2&gt;브라운아웃은 헤더의 내용을 바꾸는가&lt;/h2&gt;
&lt;p&gt;예정된 브라운아웃 때문에 헤더 값 자체가 움직일 필요는 없다. 종료 날짜는 그 이전에 리소스가
간헐적으로 실패하든 아니든 여전히 종료 날짜 그대로다. 바뀌는 것은 헤더가 아니라 응답이다.
&lt;a href=&quot;https://changeloop.dev/blog/ko/api-deprecation/&quot;&gt;API 비추천 처리&lt;/a&gt;가 설명하듯, 공지된 날짜 이전 몇 주 동안 짧은
&lt;code&gt;410 Gone&lt;/code&gt; 구간을 예약해 두면, 호출자가 그 실패를 처음 접하는 순간이 헤더의 날짜가 도래하는
당일의 실전이 아니라 예행연습이 된다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;실제 HTTP 클라이언트나 도구가 &lt;code&gt;Sunset&lt;/code&gt; 헤더를 정말로 읽는가?&lt;/strong&gt;
클라이언트 쪽에서는 드물다. 그 가치는 주로 여러분과 호출자 사이의 인프라를 운영하는 쪽을
위한 것이다. 헤더를 감시하도록 설정한 API 게이트웨이나 모니터링 도구는 호출자의 코드가 알아
차리기 훨씬 전에 자사 팀이나 파트너 팀에 경보를 보낼 수 있다. 상대편이 이미 대비하고 있다고
가정할 수 있는 신호가 아니라, 여러분이 직접 도구를 만들어 대응하는 신호로 취급하라.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Sunset&lt;/code&gt;은 &lt;code&gt;Cache-Control: max-age&lt;/code&gt;와 같은 것인가?&lt;/strong&gt;
아니다. &lt;code&gt;max-age&lt;/code&gt;는 캐시된 사본이 얼마나 오래 유효한지에 관한 것이고, &lt;code&gt;Sunset&lt;/code&gt;은 리소스 자체
가 언제 존재하지 않게 되는지에 관한 것이다. 응답은 짧은 &lt;code&gt;max-age&lt;/code&gt;와 몇 년 뒤의 &lt;code&gt;Sunset&lt;/code&gt; 날짜
를 동시에 가질 수도 있고 그 반대일 수도 있으며, 어느 헤더도 다른 헤더를 제약하지 않는다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;엔드포인트 전체가 아니라 필드 하나가 사라지는 경우에도 Sunset을 보낼 수 있는가?&lt;/strong&gt;
아니다. 이 헤더는 리소스, 즉 URL에 스코프되어 있으며 응답 본문 안의 필드에 스코프되어 있지
않다. 엔드포인트 자체는 유지된 채 사라지는 필드나 파라미터, 열거값에 대해서는 대신 &lt;code&gt;Deprecation&lt;/code&gt;
헤더와 체인지로그 항목을 사용하라. &lt;a href=&quot;https://changeloop.dev/blog/ko/api-deprecation/&quot;&gt;API 비추천 처리&lt;/a&gt;가 바로 그런
종류의 변경을 공지하는 방법을 다룬다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;종료 날짜를 옮겨야 한다면 어떻게 하는가?&lt;/strong&gt;
헤더 값을 갱신하고, 애초에 그것을 공지했던 체인지로그 항목에도 그렇게 적어라. 이미 공개된
날짜를 조용히 바꾸는 것은 호출자로 하여금 여러분의 날짜가 하나도 진짜가 아니라고 판단하게
만드는 방식이다. RFC가 이 값을 굳이 보장이 아닌 힌트로 규정한 것은 날짜가 실제로 움직일 때가
있기 때문이지만, 설명 없이 옮겨진 날짜는 다음 날짜에 대한 신뢰마저 갉아먹는다.&lt;/p&gt;
</content:encoded></item><item><title>체인지로그란 무엇이고, 무엇이 들어가야 하는가</title><link>https://changeloop.dev/blog/ko/what-is-a-changelog/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/what-is-a-changelog/</guid><description>체인지로그는 제품에서 무엇이 바뀌었는지 날짜순으로 기록한 것으로, 영향받는 사람들을 위해 쓴다. 무엇이 들어가고 어디에 두며 어떻게 배포할지 설명한다.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;체인지로그란 제품에서 무엇이 바뀌었는지를 날짜순으로 기록한 것으로, 이를 출시한 팀이 아니라 그 변경으로 영향을 받는 사람들을 위해 작성된다. 각 항목은 하나의 변경 사항을 명명하고, 언제 발효되었는지 말하며, 독자가 그것에 대해 무엇을 해야 하는지 말한다. 대부분의 항목에서 그것은 아무것도 하지 않아도 된다는 뜻이다. 바로 이 마지막 부분이 체인지로그를 커밋 로그와 구분한다. 커밋 로그는 코드를 작성한 사람들을 위한 기록이고, 체인지로그는 그것을 사용하는 사람들을 위한 기록이다.&lt;/p&gt;
&lt;h2&gt;체인지로그란 정확히 무엇인가&lt;/h2&gt;
&lt;p&gt;날짜가 적힌 항목들의 목록으로, 최신순으로 나열되며, 각각은 독자가 확인할 수 있는 용어로 하나의 변경 사항을 설명한다. 팀이 무엇을 만들었는지가 아니라 지금 무엇이 달라졌는지다. &amp;quot;결제 서비스 리팩터링&amp;quot;은 커밋 메시지다. &amp;quot;청구서가 이제 세금을 별도 항목으로 표시한다&amp;quot;는 체인지로그 항목이다. 독자가 자신의 계정에서 확인할 수 있는 무언가를 말해주기 때문이다.&lt;/p&gt;
&lt;p&gt;이 형식은 오래되었고 의도적으로 단순하다. 릴리스나 날짜마다 제목 하나, 그 아래 짧은 목록, 때로는 카테고리 레이블이 붙는다. &lt;a href=&quot;https://keepachangelog.com/en/1.1.0/&quot;&gt;Keep a Changelog&lt;/a&gt;는 이 형식에서 가장 많이 인용되는 명세이며, 존재하는 이유는 명세를 건너뛴 대부분의 프로젝트가 결국 커밋 히스토리를 그대로 쏟아내는 것으로 끝나기 때문인데, 이는 독자가 가지고 온 질문과는 다른 질문에 답하는 것이다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;문서&lt;/th&gt;
&lt;th&gt;대상&lt;/th&gt;
&lt;th&gt;답하는 질문&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;체인지로그&lt;/td&gt;
&lt;td&gt;제품을 사용하는 모든 사람&lt;/td&gt;
&lt;td&gt;무엇이 바뀌었고, 언제인가?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;커밋 로그&lt;/td&gt;
&lt;td&gt;코드를 작성한 팀&lt;/td&gt;
&lt;td&gt;무엇이 어떤 순서로 이루어졌는가?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;릴리스 노트&lt;/td&gt;
&lt;td&gt;업데이트 여부를 결정하는 사용자&lt;/td&gt;
&lt;td&gt;이제 예전에 못 하던 무엇을 할 수 있는가?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;패치 노트&lt;/td&gt;
&lt;td&gt;특정 수정 사항의 이용자&lt;/td&gt;
&lt;td&gt;이 릴리스가 정확히 무엇을 고쳤는가?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;로드맵&lt;/td&gt;
&lt;td&gt;다음에 무엇이 올지 궁금한 모든 사람&lt;/td&gt;
&lt;td&gt;무엇이 계획되어 있고, 얼마나 진행되었는가?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;이 다섯 가지는 실제로는 겹치지만 같은 문서가 아니며, 차이는 읽는 순간 누가 그것을 손에 들고 있는가에 있다. 체인지로그는 나중에 검색되고 다시 링크되도록 만들어진 것이어서, 그 항목들은 다른 것들보다 안정적인 날짜와 URL을 더 필요로 한다.&lt;/p&gt;
&lt;h2&gt;체인지로그 항목에는 실제로 무엇이 들어가는가&lt;/h2&gt;
&lt;p&gt;네 가지, 이 순서대로다. 무엇이 바뀌었는지, 사용자나 호출자가 알아챌 용어로 표현된 것. 언제 발효되었는지. 어느 카테고리에 속하는지(added, fixed, changed, removed가 흔한 네 가지다). 그리고 중요할 때는 독자가 그것에 대해 무엇을 해야 하는지. 더 자세한 내용으로의 링크는 환영받는다. 내부적인 정당화 문단은 그렇지 않다. 독자는 왜냐고 묻지 않았고, 무엇이냐고 물었기 때문이다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;## 2026-09-07

### Added
- 청구서가 이제 고객 계정 통화로 세금을 별도 항목으로 표시한다.

### Fixed
- 보고서를 CSV로 내보낼 때 보고서가 10,000행을 넘어도 더 이상
  마지막 행을 잃지 않는다.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 형식은 구조를 바꾸지 않고도 두 줄짜리 업데이트부터 한 릴리스에 수록된 백 개의 항목까지 확장된다. 이것이 어떤 형식이 실제로 작동하는지에 대한 진짜 테스트다. 바쁜 주에도 조용한 주에도 똑같이 읽히는가.&lt;/p&gt;
&lt;h2&gt;누가 체인지로그를 쓰고, 언제 쓰는가&lt;/h2&gt;
&lt;p&gt;변경을 실제로 만든 사람이, 출시되는 순간에 쓴다. 일주일 후 티켓에서 재구성하는 기술 작가가 아니다. 코드를 만진 사람은 사용자에게 실제로 무엇이 바뀌었는지 안다. 나중에 쓰인 요약은 실제로 출시된 것보다 티켓을 설명하는 경향이 있으며, 이는 대체로 실제 범위보다 넓거나 좁다. 일부 팀은 항목이 공개되기 전에 검토 단계를 추가하는데, 주로 스며든 내부 언어를 잡아내기 위해서이며, 그 검토는 항목이 같은 날 나갈 만큼 충분히 빨라야 한다.&lt;/p&gt;
&lt;h2&gt;체인지로그는 어디에 있어야 하는가&lt;/h2&gt;
&lt;p&gt;안정적인 URL을 가진 자체 페이지에, 피드로 배포된다. 설정 메뉴나 코드 호스트의 릴리스 태그에 파묻혀 있으면 어디를 봐야 하는지 이미 알고 있던 사람들에게만 닿는다. 공개 페이지는 지원 티켓에서 링크되고, 리뷰에서 인용되고, 구독될 수 있다. 피드는 페이지만큼 중요하다. 제품의 체인지로그를 한 달에 한 번 확인하는 독자는 드물고, 구독하는 독자는 그렇지 않으며, 오직 피드만이 후자를 위한다.&lt;/p&gt;
&lt;h2&gt;릴리스 노트와는 어떻게 다른가&lt;/h2&gt;
&lt;p&gt;이 둘은 끊임없이 혼동되며, 섞으면 어느 쪽 독자도 제대로 만족시키지 못하는 문서가 나올 만큼 다르다. &lt;a href=&quot;https://changeloop.dev/blog/ko/changelog-vs-release-notes/&quot;&gt;체인지로그 대 릴리스 노트&lt;/a&gt;가 이 차이를 완전히 다룬다. 짧게 말하면, 체인지로그는 완전하고 시간순인 기록이고, 릴리스 노트는 업데이트가 가질 가치가 있는 것처럼 들리도록 쓰인 선별된 부분집합이다. 제품은 보통 둘 다 필요하며, 독자의 하루 중 서로 다른 순간을 겨냥한다.&lt;/p&gt;
&lt;h2&gt;무엇이 체인지로그를 읽을 가치가 있게 만드는가&lt;/h2&gt;
&lt;p&gt;자기 범위에 대한 구체성과 정직함이다. &amp;quot;다양한 버그 수정&amp;quot;은 독자에게 페이지를 그만 열게 만드는 문장이다. 확인할 수 있는 것을 아무것도 약속하지 않기 때문이다. 작은 수정이라도 정확히 바뀐 동작을 명명한 항목이 구독을 살아있게 만드는 항목이다. 이 원칙은 생략하는 것에도 적용된다. 성공만 발표하고 고장 난 것에 대한 수정은 절대 발표하지 않는 체인지로그는 체인지로그 옷을 입은 마케팅처럼 읽히며, 독자는 그것을 알아챈다.&lt;/p&gt;
&lt;p&gt;버전 관리 원칙도 중요하다. &lt;a href=&quot;https://changeloop.dev/blog/ko/semantic-versioning-changelog/&quot;&gt;시맨틱 버저닝과 당신의 체인지로그&lt;/a&gt;는 버전 번호와 항목이 어떻게 일치해야 하는지 보여준다. 버전 히스토리를 훑어보는 독자가 두 개의 다른 신호가 아니라 같은 신호를 두 번 받도록 하기 위해서다.&lt;/p&gt;
&lt;h2&gt;체인지로그는 어떻게 생성되는가&lt;/h2&gt;
&lt;p&gt;두 가지 방식이 있고, 대부분의 실제 설정은 둘의 혼합이다. 자동 생성은 커밋 메시지를 읽는데, 보통 &lt;a href=&quot;https://www.conventionalcommits.org/en/v1.0.0/&quot;&gt;Conventional Commits&lt;/a&gt; 형식이며, 아무도 결과물을 건드리지 않고 항목으로 바꾼다. &lt;a href=&quot;https://changeloop.dev/blog/ko/conventional-commits-changelog/&quot;&gt;Conventional Commits에서 체인지로그로&lt;/a&gt;가 그 파이프라인을 다룬다. 선별 생성은 누군가가 각 항목을 손으로 쓰거나 편집한다는 뜻이다. 자동화된 결과물은 더 빠르고 병합된 풀 리퀘스트를 절대 놓치지 않지만, 모호한 커밋 메시지를 그대로 물려받는다. 그래서 자동화하는 대부분의 팀도 원본 결과물을 그대로 보여주기보다는 게시 전에 가벼운 편집 단계를 유지한다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;모든 제품에 체인지로그가 필요한가?&lt;/strong&gt;
변경으로 영향을 받는 사용자가 있는 제품이라면, SaaS 앱이든 내부 도구든 공개 API든 필요하다. 형식은 적응하지만(API 체인지로그는 소비자 앱과는 다르게 읽힌다) 필요성은 그렇지 않다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;소프트웨어 용어로 체인지로그란 무엇인가?&lt;/strong&gt;
위와 같은 정의다. 소프트웨어에서 무엇이 바뀌었는지에 대한, 날짜가 적힌 시간순 목록으로, 그것을 만든 사람이 아니라 사용하는 사람을 위해 작성된다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;체인지로그는 커밋에서 자동으로 생성될 수 있는가?&lt;/strong&gt;
그렇다. 많은 팀이 정확히 그렇게 하며, 보통 Conventional Commits 형식의 메시지에서 생성한다. 절충안은 생성된 항목이 그 출처인 커밋 메시지만큼만 명확하다는 것이어서, 게시 전 검토 과정이 재구성이 필요한 항목을 잡아낸다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;체인지로그는 버전 히스토리와 같은 것인가?&lt;/strong&gt;
용어가 서로 바꿔 쓰일 만큼 가깝다. 버전 히스토리는 때로 설명 없이 버전 번호와 날짜만 나열한 목록에 불과하다. 체인지로그는 항상 무엇이 바뀌었는지를 포함한다.&lt;/p&gt;
</content:encoded></item><item><title>API 체인지로그: 무엇을 공개하고 누가 읽는가</title><link>https://changeloop.dev/blog/ko/api-changelog/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/api-changelog/</guid><description>API 체인지로그는 내 코드가 다음 달에도 작동할지 판단하려는 사람이 읽는다. 각 항목이 독자에게 져야 할 책임과 위치, 구독 방법을 설명한다.</description><pubDate>Wed, 02 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;API 체인지로그란 호출자가 알아챌 수 있는 모든 변경 사항을 날짜순으로 기록한 것으로, 이를 출시하는 팀이 아니라 그 API와 통합하는 사람들을 위해 작성된다. 이 독자층이야말로 그것을 제품 체인지로그와는 다른 문서로 만든다. 독자는 자신의 코드가 다음 달에도 계속 작동할지를 판단하고 있는 것이다. 대부분의 API 체인지로그는 같은 방식으로 실패한다. 내부 릴리스 피드를 걸러낸 사본에 지나지 않아서, 제거된 필드가 문구 수정과 똑같은 무게로 나란히 놓이고, 둘 다 읽히지 않는다.&lt;/p&gt;
&lt;h2&gt;API 체인지로그란 무엇인가&lt;/h2&gt;
&lt;p&gt;다른 사람들이 그것에 대해 코드를 작성한 인터페이스의 변경 사항을 담은, 공개되고 날짜가 적힌 기록이다. 무언가가 여기에 속하는지 판단하는 유용한 테스트는 그 변경이 내부적으로 얼마나 컸는지와는 아무 상관이 없다. 이 테스트는 작년에 작성되고 그 이후로 손대지 않은 올바른 호출자가 그것 때문에 다르게 동작할 수 있는지를 묻는다. 이 테스트는 아주 작은 변경 일부는 받아들이고 아주 큰 변경 일부는 제외한다.&lt;/p&gt;
&lt;p&gt;아래의 모든 내용은 호출자가 회사 밖에 있고 이 문서 외에는 사실상 닿을 수 없다고 가정한다. 호출자가 같은 회사의 다른 팀일 때는 계산이 충분히 달라져서 그 자체로 다뤄질 가치가 있다. &lt;a href=&quot;https://changeloop.dev/blog/ko/internal-api-changelog/&quot;&gt;내부용 API 체인지로그&lt;/a&gt;는 그 독자에게 대신 무엇이 필요한지를 다룬다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;문서&lt;/th&gt;
&lt;th&gt;독자&lt;/th&gt;
&lt;th&gt;답하는 질문&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;API 체인지로그&lt;/td&gt;
&lt;td&gt;API를 호출하는 개발자&lt;/td&gt;
&lt;td&gt;내 통합이 아직도 작동하는가?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;릴리스 노트&lt;/td&gt;
&lt;td&gt;제품 사용자&lt;/td&gt;
&lt;td&gt;이제 예전에 못 하던 무엇을 할 수 있는가?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;비추천 공지&lt;/td&gt;
&lt;td&gt;특정 한 가지를 호출하는 사람&lt;/td&gt;
&lt;td&gt;이것은 언제 작동을 멈추는가?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;상태 페이지&lt;/td&gt;
&lt;td&gt;지금 영향을 받는 모두&lt;/td&gt;
&lt;td&gt;지금 서비스가 다운되었는가?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;마이그레이션 가이드&lt;/td&gt;
&lt;td&gt;업그레이드하는 호출자&lt;/td&gt;
&lt;td&gt;A에서 B로 어떻게 옮기는가?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;a href=&quot;https://changeloop.dev/blog/ko/api-migration-guide/&quot;&gt;API 마이그레이션 가이드는 어떻게 작성하는가&lt;/a&gt;가 이 마지막 문서를 완전히 다룬다. 짧게 말하면, 이것은 호환되지 않는 변경 항목이 대체하려 하는 대신 링크해야 하는 것이다.&lt;/p&gt;
&lt;p&gt;이 다섯 가지는 각기 다른 수명 주기를 가진 별개의 문서다. 비추천 공지는 날짜가 적힌 약속이며 체인지로그에도 속하지만, 체인지로그 항목은 한 번 작성되는 반면 비추천은 서비스 종료까지 추적된다. 이 둘을 뒤섞는 것이 서비스 종료를 놓치는 이유다.&lt;/p&gt;
&lt;h2&gt;하나의 항목에는 무엇이 들어가야 하는가&lt;/h2&gt;
&lt;p&gt;여섯 가지가 있고, 처음 세 가지가 보통 빠져 있는 것들이다. 내부 컴포넌트가 아니라 요청이나 응답의 관점에서 표현된 변경 사항. 올바른 호출자를 깨뜨리는지 여부. 호출자가 해야 할 일, &amp;quot;아무것도 없음&amp;quot;을 포함해서. 발효된 날짜. 영향을 받는 버전 또는 버전들. 존재한다면 마이그레이션 가이드로의 링크.&lt;/p&gt;
&lt;p&gt;&amp;quot;accounts 엔드포인트 개선됨&amp;quot;이라고 말하는 항목은 여섯 가지 모두에서 실패한다. &amp;quot;&lt;code&gt;accounts.type&lt;/code&gt; 필드가 이전에 &lt;code&gt;personal&lt;/code&gt;을 반환하던 곳에서 이제 &lt;code&gt;individual&lt;/code&gt;을 반환한다. 9월 2일 이전에 생성된 계정은 기존 값이 변경되지 않는다. 문자열을 비교하지 않는 한 조치가 필요하지 않다&amp;quot;라고 말하는 항목은 한 문장으로 여섯 가지 모두에 답한다.&lt;/p&gt;
&lt;p&gt;부서가 아니라 결과에 따라 항목을 분류하라. 세 가지 라벨이 거의 모든 가치를 담는다. breaking, additive, fixed다. &lt;a href=&quot;https://semver.org/&quot;&gt;Semantic Versioning&lt;/a&gt;은 이미 처음 두 가지를 정확하게 정의하고 있으며, 독자적인 정의를 만들어내는 대신 그 정의를 빌려오는 것은 semver를 아는 독자가 여러분의 라벨을 이해한다는 뜻이다. &lt;a href=&quot;https://keepachangelog.com/en/1.1.0/&quot;&gt;Keep a Changelog&lt;/a&gt;는 원한다면 더 긴 세트를 제공하며, 그 핵심 규칙은 다른 어디서보다 여기서 더 강하게 적용된다. 로그는 사람을 위한 것이고, 커밋 제목 덤프는 그렇지 않다.&lt;/p&gt;
&lt;h2&gt;API 체인지로그는 릴리스 노트와 어떻게 다른가&lt;/h2&gt;
&lt;p&gt;릴리스 노트는 제품이 이제 무엇을 할 수 있는지 설명한다. API 체인지로그는 계약이 이제 무엇인지 설명한다. 동일한 출시 작업이 흔히 두 문서 모두에 항목을 만들어내지만, 서로 다르게 표현된다. 독자층이 필요로 하는 것이 다르기 때문이다. 새로운 내보내기 형식은 사용자에게는 기능이고, 그 필드로 분기하는 호출자에게는 새로운 enum 값이다.&lt;/p&gt;
&lt;p&gt;실질적인 결과는 이 둘이 스타일만 다른 같은 피드가 될 수 없다는 것이다. 여러분이 출시하는 모든 것을 구독하는 호출자는 결국 구독을 취소하게 되고, 그러면 파괴적 변경을 놓치게 된다. 하나의 피드를 발행한다면 필터링하라. 둘을 발행한다면 API용은 더 좁게 만들고 마케팅 항목이 절대 들어가지 않게 하라. 두 형태를 나란히 &lt;a href=&quot;https://changeloop.dev/blog/ko/changelog-vs-release-notes/&quot;&gt;체인지로그 대 릴리스 노트&lt;/a&gt;에서 비교한다.&lt;/p&gt;
&lt;h2&gt;API 체인지로그는 어디에 있어야 하는가&lt;/h2&gt;
&lt;p&gt;참조 문서 옆에, 안정적인 URL로, 각 항목이 프래그먼트나 자체 경로를 통해 개별적으로 주소 지정될 수 있게. 호출자는 사고 분석과 내부 티켓에서 항목을 링크한다. 링크할 수 없는 항목은 대신 스크린샷으로 붙여넣어진다.&lt;/p&gt;
&lt;p&gt;페이지뿐 아니라 기계가 읽을 수 있는 출력으로도 발행하라. &lt;a href=&quot;https://www.jsonfeed.org/version/1.1/&quot;&gt;JSON Feed 사양&lt;/a&gt;을 따르는 JSON 피드나 &lt;a href=&quot;https://www.rssboard.org/rss-specification&quot;&gt;RSS 피드&lt;/a&gt;는 항목이 구조화된 데이터가 되는 순간 아무런 비용도 들지 않으며, 이것이야말로 고객이 여러분의 변경 사항을 자신들의 릴리스 프로세스에 통합할 수 있게 해주는 것이다. 이것은 또한 누군가가 그 위에 무언가를 구축할지를 결정하는 부분이기도 하다. GitHub는 같은 이유로 &lt;a href=&quot;https://docs.github.com/en/rest/about-the-rest-api/api-versions&quot;&gt;REST API 버전&lt;/a&gt;을 참조 바로 옆에 문서화한다. 버전 정책은 인터페이스의 일부이기 때문이다.&lt;/p&gt;
&lt;h2&gt;실제로 좋은 항목은 어떤 모습인가&lt;/h2&gt;
&lt;p&gt;같은 주간의 세 항목을, 위에서 설명한 형태로 보여준다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2026-09-02  Breaking  v2
  `POST /invoices`는 이제 고객 계정 통화와 일치하지 않는 `currency`를
  거부하며, 조용히 변환하는 대신 422를 반환한다. 변환에 의존했던
  호출자는 계정 통화를 보내야 한다. v2에만 영향을 미친다. v1은
  2027-01-15의 서비스 종료까지 변경되지 않는다.

2026-09-02  Additive  v1, v2
  `Invoice`는 청구서가 결제될 때까지 null인 `settled_at` 타임스탬프를
  얻는다. 조치가 필요하지 않다. 알 수 없는 필드를 거부하는 클라이언트는
  업데이트되어야 한다.

2026-08-31  Fixed  v2
  `GET /invoices?status=`는 알 수 없는 상태에 대해 400 대신 빈 페이지를
  반환했다. 이제는 허용되는 값과 함께 400을 반환한다. 오타를 낸
  호출자는 이전에는 결과가 0개였지만 이제는 오류를 본다.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;세 번째는 내부적으로 버그 수정이기 때문에 가장 자주 생략되는 유형이다. 그 빈 페이지 주위에 재시도 로직을 구축한 호출자에게는 이것이 동작 변경이며, 항목이야말로 지원 티켓을 막아주는 것이다. 라벨은 fixed라고 말하고 본문은 호출자가 알아챌 수 있는 것을 말한다. 이 구분이야말로 모든 수정을 파괴적 변경으로 부풀리지 않으면서 로그를 정직하게 유지하는 것이다.&lt;/p&gt;
&lt;h2&gt;호출자는 어떻게 구독하는가&lt;/h2&gt;
&lt;p&gt;호출자에게 하나 이상의 채널을 제공하라. 그들의 임무가 다르기 때문이다. 모든 것을 원하는 개발자를 위한 피드. 파괴적 변경만 원하는 사람을 위한 이메일. 코드 자체를 위한 응답 헤더는 확인을 절대 잊지 않는 유일한 구독자다. &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc8594&quot;&gt;RFC 8594에 정의된 &lt;code&gt;Sunset&lt;/code&gt; 헤더&lt;/a&gt;는 서비스 종료 날짜를 응답에 담아, 클라이언트 라이브러리가 그것을 로그로 남길 수 있게 한다.&lt;/p&gt;
&lt;p&gt;대부분의 팀이 놓치는 채널은 직접적인 것이다. 어떤 호출자가 지난주에 여러분이 바꾸려는 필드를 사용했다면, 그가 누구인지 알고 있는 것이다. 그 계정들에 보내는 이메일은 어떤 규모의 일괄 발송보다도 가치가 크다. 이것은 아무도 요청하지 않은 변경에 적용된 &lt;a href=&quot;https://changeloop.dev/blog/ko/customer-feedback-loop/&quot;&gt;고객 피드백 루프 닫기&lt;/a&gt;와 같은 원칙이다. 영향을 받은 사람들은 개별적으로 통보받고, 나머지 모두는 피드를 받는다. 웹훅은 의존하기 전에 알아둘 가치가 있는 자기만의 실패 방식을 가진 네 번째 채널이다. &lt;a href=&quot;https://changeloop.dev/blog/ko/webhook-changelog/&quot;&gt;웹훅 체인지로그&lt;/a&gt;는 그곳에서의 페이로드 변경이 왜 새 형태를 거부할 호출자 없이 조용히 깨지는지를 다룬다.&lt;/p&gt;
&lt;h2&gt;파괴적 변경을 위한 항목은 어떻게 작성하는가&lt;/h2&gt;
&lt;p&gt;이유가 아니라 파괴 자체로 시작하라. 열 개의 항목을 훑어보는 호출자는 첫 문장에서 이것이 자신에게 작업을 발생시킬지 알아야 한다. 그다음 날짜, 영향을 받는 버전, 마이그레이션, 그리고 예전 동작이 변경되는 것이 아니라 사라지는 경우의 마감일.&lt;/p&gt;
&lt;p&gt;같은 내용을 비추천 공지, 응답 헤더, 직접 이메일에 일관되게 표현하여 넣고, 넷 모두에 같은 날짜를 부여하라. 이들 사이의 불일치는 계획된 변경을 사고로 바꾸는 실패다. 그중 하나만 읽은 호출자가 잘못된 날짜에 따라 행동하기 때문이다. &lt;a href=&quot;https://changeloop.dev/blog/ko/breaking-changes/&quot;&gt;파괴적 변경이란 무엇인가&lt;/a&gt;는 그 결정 자체를 다루고, &lt;a href=&quot;https://changeloop.dev/blog/ko/api-deprecation/&quot;&gt;API를 비추천 처리하는 방법&lt;/a&gt;은 그 뒤에 이어지는 일정을 다룬다.&lt;/p&gt;
&lt;p&gt;changeloop에서는 pull request가 병합되고, 누군가 초안을 편집하고 승인하며, 그 항목이 &lt;a href=&quot;https://changeloop.dev/docs&quot;&gt;피드와 위젯&lt;/a&gt;에 발행될 때 API 변경이 항목이 된다. 바로 그 순간, 위젯 피드백이 GitHub 이슈가 되었고 pull request가 그 이슈를 닫는 호출자는 그 이슈에서 통보를 받는다. 여기서 중요한 것은 검토 단계다. API 체인지로그는 계약 문서이며, 사람이 읽지 않은 초안이 호출자에게 도달해서는 안 된다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;모든 API 변경에 체인지로그 항목이 필요한가?&lt;/strong&gt;
올바른 호출자가 알아챌 수 있는 모든 변경은 그렇다. 내부적이라고 여기는 것들도 포함해서. 요청이나 응답에 관찰 가능한 영향이 없는 변경은 아니며, 그것들을 추가하면 독자가 대충 훑어보도록 훈련시키게 된다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;API 체인지로그는 문서에 있어야 하는가, 마케팅 사이트에 있어야 하는가?&lt;/strong&gt;
문서에, 참조 바로 옆에. 독자는 보통 이미 거기에 있으며, 마케팅 사이트의 체인지로그는 그것이 쓰이지 않은 독자층을 얻는 경향이 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;얼마나 과거까지 거슬러 올라가야 하는가?&lt;/strong&gt;
무한정. 항목은 몇 년 후에도 사고 분석에서 인용되며, 잘려나간 로그는 그 링크들을 깨뜨린다. 잘라내는 대신 페이지네이션을 사용하라.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;API 버전마다 별도의 체인지로그가 필요한가?&lt;/strong&gt;
아니다. 항목마다 버전 필드가 있는 하나의 로그가 읽기와 검색이 더 쉽다. 버전별 필터링은 페이지의 기능이지, 문서를 나눌 이유가 아니다.&lt;/p&gt;
</content:encoded></item><item><title>사람들이 계속 찾아오는 체인지로그 페이지 만드는 법</title><link>https://changeloop.dev/blog/ko/changelog-page/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/changelog-page/</guid><description>체인지로그 페이지는 사람들이 다시 돌아올 때 가치가 있다. 어디에 둘지, 항목에 무엇이 필요한지, 피드와 마크업, 위젯과의 관계를 설명한다.</description><pubDate>Wed, 02 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;체인지로그 페이지는 사람들이 다시 돌아올 것이라면 만들 가치가 있다. 이것은 단순히 그것을 가지고 있는 것보다 더 높은 기준이며, 대부분이 걸려 넘어지는 기준이기도 하다. 존재하고, 푸터에 링크되어 있고, 몰아서 업데이트되며, 사고가 났을 때 말고는 아무도 방문하지 않는 페이지. 이 둘을 가르는 결정은 무언가 쓰이기 전에 내려지며, 대부분은 페이지가 어디에 있어야 하는지와 같은 콘텐츠에서 또 무엇이 생성되는지에 관한 것이다.&lt;/p&gt;
&lt;h2&gt;체인지로그 페이지란 무엇인가&lt;/h2&gt;
&lt;p&gt;제품에서 무엇이 바뀌었는지를 보여주는, 여러분 소유의 URL에 있는 공개되고 날짜가 적힌 목록이다. 같은 항목이 나타날 수 있는 다섯 가지 표면 중 하나이며, 유용한 질문은 어느 것을 고를지가 아니라 어느 것이 정본이고 어느 것이 거기서 생성되는지다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;표면&lt;/th&gt;
&lt;th&gt;가장 적합한 용도&lt;/th&gt;
&lt;th&gt;비용&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;호스팅된 페이지&lt;/td&gt;
&lt;td&gt;검색, 링크, 긴 기록&lt;/td&gt;
&lt;td&gt;URL과 템플릿&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;앱 내 위젯&lt;/td&gt;
&lt;td&gt;페이지를 절대 방문하지 않는 사용자에게 도달&lt;/td&gt;
&lt;td&gt;임베드, 그리고 절제&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;문서 섹션&lt;/td&gt;
&lt;td&gt;API 및 개발자 독자층&lt;/td&gt;
&lt;td&gt;참조 옆에 두는 것&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JSON 피드&lt;/td&gt;
&lt;td&gt;여러분의 변경 사항 위에 구축하는 고객&lt;/td&gt;
&lt;td&gt;이미 가지고 있는 구조&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RSS 피드&lt;/td&gt;
&lt;td&gt;한 번 구독하는 개발자&lt;/td&gt;
&lt;td&gt;거의 아무것도 아님&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;정본이 되는 하나의 소스를 고르고, 한 번 발행하고, 나머지는 거기서 생성하라. 페이지와 위젯을 손으로 따로 유지하는 팀은 결국 서로 맞지 않는 두 개의 텍스트를 갖게 되고, 그 불일치는 고객이 발견한다.&lt;/p&gt;
&lt;h2&gt;체인지로그 페이지는 어디에 있어야 하는가&lt;/h2&gt;
&lt;p&gt;여러분 자신의 도메인에, 안정적인 경로로, 각 항목이 개별적으로 주소 지정될 수 있게. 세 가지 흔한 위치는 메인 사이트의 경로, 서브도메인, 문서의 한 섹션이다. 메인 사이트의 경로는 반대할 논거를 찾아야 하는 기본 선택지이지, 찬성할 논거를 찾을 것이 아니다. 사이트의 권위를 물려받고, 추가 인증서나 DNS가 필요 없으며, 페이지를 다른 모든 것과 같은 내비게이션에 유지한다.&lt;/p&gt;
&lt;p&gt;서브도메인이 옳은 답이 되는 경우는 페이지가 마케팅 사이트와 다른 시스템에서 서비스될 때이며, 그렇지 않으면 프록시를 해야 할 것이다. 그 대가는 권위가 따로 쌓인다는 것이다. 체인지로그를 문서에 두는 것이 옳은 경우는 독자층이 개발자일 때이며, 그 이유는 &lt;a href=&quot;https://changeloop.dev/blog/ko/api-changelog/&quot;&gt;API 체인지로그&lt;/a&gt;에서 다룬다. 독자는 보통 이미 거기에 있다.&lt;/p&gt;
&lt;p&gt;선택보다 더 중요한 것은 항목이 개별적으로 링크될 수 있어야 한다는 점이다. 사람들은 사고 분석과 내부 티켓에서 항목을 링크한다. &amp;quot;체인지로그, 아래로 스크롤하세요&amp;quot;로만 링크할 수 있는 항목은 대신 스크린샷으로 붙여넣어진다.&lt;/p&gt;
&lt;h2&gt;체인지로그 페이지에는 무엇이 필요한가&lt;/h2&gt;
&lt;p&gt;다섯 가지가 있고, 처음 두 가지에서 대부분의 페이지가 실패한다. 변경 사항마다 날짜가 적힌 항목, 최신순으로. 관심 있는 유형별로 훑어볼 수 있도록 항목마다 카테고리나 라벨. 항목마다 고유 링크. 구독 경로. 약 50개 항목이 넘으면 검색이나 필터.&lt;/p&gt;
&lt;p&gt;나머지는 선택 사항이다. 스크린샷은 도움이 되지만 유지 관리 비용이 든다. 저자 이름은 어떤 제품에서는 신뢰를 쌓고 다른 제품에서는 잡음이 된다. 버전 번호는 API 호출자에게는 중요하지만 그 외 거의 누구에게도 중요하지 않다. &lt;a href=&quot;https://keepachangelog.com/en/1.1.0/&quot;&gt;Keep a Changelog&lt;/a&gt;는 직접 라벨을 만들 이유가 없다면 합리적인 기본값이며, 나머지를 버리더라도 지킬 가치가 있는 핵심 규칙을 담고 있다. 로그는 사람을 위해 쓰인다는 것이다.&lt;/p&gt;
&lt;p&gt;여러분의 제품이 연속적으로 출시된다면 버전이 아니라 날짜로 그룹화하라. &amp;quot;이것이 9일의 사고 전이었는지 후였는지&amp;quot;를 훑어보는 독자는 날짜를 찾고 있으며, 버전 번호로 정리된 페이지는 그에게 계산을 강요한다.&lt;/p&gt;
&lt;h2&gt;페이지인가, 앱 내 위젯인가&lt;/h2&gt;
&lt;p&gt;둘 다, 하나의 소스에서. 페이지는 검색, 링크, 긴 기록이 있는 곳이다. 위젯은 페이지를 절대 방문하지 않을 대다수 사용자에게 도달하는 방법이며, 그것이 작동하는 이유는 그들이 이미 사용하고 있는 제품 안에 나타나기 때문이다.&lt;/p&gt;
&lt;p&gt;위젯의 실패는 방해다. 모든 항목에 주의를 요구하는 배지는 일주일 안에 영구적으로 무시되며, 이는 정말로 중요했던 항목을 위한 채널을 잃게 만든다. 독자가 마지막으로 본 이후로 읽지 않은 것을 세고, 첫 방문 시 조용히 카운터를 심어서 아무도 1년치 기록의 배지로 맞이하지 않게 하고, 독자 스스로 열게 하라. 대신 열어주지 마라.&lt;/p&gt;
&lt;h2&gt;체인지로그 페이지를 기계가 읽을 수 있게 만드는 법&lt;/h2&gt;
&lt;p&gt;같은 항목을 피드로도 발행하라. &lt;a href=&quot;https://www.jsonfeed.org/version/1.1/&quot;&gt;JSON 피드&lt;/a&gt;는 코드에서 그것을 소비하는 모든 것에 마찰이 가장 적은 선택지이며, &lt;a href=&quot;https://www.rssboard.org/rss-specification&quot;&gt;RSS 피드&lt;/a&gt;는 리더에서 구독하는 개발자가 기대하는 것이다. 항목이 손으로 작성한 HTML 대신 구조화된 데이터가 되는 순간 둘 다 비용이 적게 든다. 이것이야말로 정본 사본을 구조화된 상태로 유지해야 하는 진짜 이유다.&lt;/p&gt;
&lt;p&gt;페이지도 마크업하라. 항목은 날짜와 제목이 있는 작품이고, &lt;a href=&quot;https://schema.org/CreativeWork&quot;&gt;schema.org&lt;/a&gt;가 그 어휘를 제공한다. 이것은 고유 링크와 같은 이유로 가치가 있다. 브라우저가 아닌 것들, 고객 자신의 릴리스 프로세스를 포함해서, 페이지를 사용할 수 있게 만든다. 근본적인 항목이 애초에 구조화된 데이터였던 적이 없다면 이 중 어느 것도 작동하지 않는다; &lt;a href=&quot;https://changeloop.dev/blog/ko/changelog-file-formats/&quot;&gt;체인지로그 파일 형식&lt;/a&gt;은 이 피드와 이 마크업이 실제로 생성되는 진실의 원천으로서 Markdown, JSON, YAML이 각각 무엇을 대가로 치르는지 다룬다.&lt;/p&gt;
&lt;h2&gt;체인지로그 페이지는 SEO에 도움이 되는가&lt;/h2&gt;
&lt;p&gt;간접적으로, 그리고 천천히. 개별 항목은 누군가 입력하는 어떤 검색어도 노리지 않기 때문에 순위에 잘 오르지 않는다. 페이지는 링크를 통해 자기 자리를 얻는다. 항목은 지원 답변, 포럼, 사고 분석에서 인용되며, 그 링크들은 여러분 소유의 URL에 쌓인다. 2년 동안 매주 업데이트되는 페이지는 그것이 속한 제품에 대한 신뢰할 만한 신선함 신호이기도 하다.&lt;/p&gt;
&lt;p&gt;효과가 없는 것은 항목을 콘텐츠 마케팅처럼 다루는 것이다. 길이를 위해 세 문단으로 부풀려진 항목은 진짜 임무, 즉 독자가 사용하는 무언가가 바뀌었는지를 한 문장으로 말해주는 일을 더 못하게 된다. 체인지로그가 검색을 지원하기를 원한다면, 노력을 고유 링크, 피드, 그리고 그것으로 향하는 내부 링크에 쏟고, 항목은 짧게 유지하라. 우리 자신의 &lt;a href=&quot;https://changeloop.dev/changelog-examples&quot;&gt;체인지로그 예시&lt;/a&gt; 페이지는 이 균형을 잘 잡는 페이지들을 모아놓았다.&lt;/p&gt;
&lt;h2&gt;사람들은 어떻게 구독하는가&lt;/h2&gt;
&lt;p&gt;이미 사용하는 경로를 제공하라. 개발자를 위한 RSS나 JSON 피드, 중요한 것만 듣고 싶은 사람을 위한 이메일, 그리고 둘 다 절대 하지 않을 모두를 위한 앱 내 위젯. 짐작하지 말고 무엇을 듣고 싶은지 물어보라. 파괴적 변경을 원하는데 문구 수정을 받는 독자는 둘 다에서 구독을 취소하기 때문이다.&lt;/p&gt;
&lt;p&gt;마지막으로 추가해야 할 경로는 루프를 닫는 경로다. 어떤 항목이 특정 사람이 요청한 것을 해결했을 때, 그가 페이지를 읽어주기를 바라는 대신 직접 알려주라. changeloop에서는 항목이 &lt;a href=&quot;https://changeloop.dev/docs&quot;&gt;페이지, 피드, 위젯&lt;/a&gt;에 한 번에 발행되며, 위젯 피드백이 pull request가 닫은 GitHub 이슈가 된 사람은 그 이슈에서 항목으로의 링크와 함께 통보받고, 위젯에서도 그 항목을 보게 된다. 메커니즘은 다른 구독과 동일하다. 차이는 수신자가 이미 물어봤다는 것이다. 이것이 &lt;a href=&quot;https://changeloop.dev/blog/ko/customer-feedback-loop/&quot;&gt;체인지로그 쪽에서 피드백 루프 닫기&lt;/a&gt;에서 전개된 주장이다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;체인지로그 페이지는 서브도메인에 있어야 하는가, 경로에 있어야 하는가?&lt;/strong&gt;
기본적으로 메인 사이트의 경로다. 사이트의 권위를 물려받고 추가 인프라가 필요하지 않기 때문이다. 서브도메인은 다른 시스템이 페이지를 서비스할 때 정당화된다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;페이지는 한 번에 몇 개의 항목을 보여줘야 하는가?&lt;/strong&gt;
화면을 채울 만큼, 그 이상은 아니고, 이후에는 페이지네이션. 2년치 기록을 하나의 문서에 로드하는 것은 느리고 최신 항목을 찾기 어렵게 만든다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;오래된 항목은 언젠가 삭제해야 하는가?&lt;/strong&gt;
아니다. 여러분 사이트 밖에서 인용되고 있으며, 링크가 깨진다. 항목은 그 자리에서 메모와 함께 수정하고, URL은 계속 살아 있게 하라.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;모든 변경 사항이 페이지에 나타나야 하는가?&lt;/strong&gt;
사용자가 알아챌 수 있는 것만. 내부 리팩터링을 기록하는 페이지는 독자가 대충 훑어보도록 훈련시키며, 대충 훑어지는 페이지는 긴급한 무언가를 담고 있는 날 실패한다.&lt;/p&gt;
</content:encoded></item><item><title>실제로 읽히는 제품 업데이트 이메일 템플릿</title><link>https://changeloop.dev/blog/ko/product-update-email/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/product-update-email/</guid><description>읽히는 제품 업데이트 이메일은 그것을 요청한 사람에게 도착한 이메일이다. 템플릿 구조, 네 가지 유형, 제목 짓는 법, 세그멘테이션과 동의를 설명한다.</description><pubDate>Wed, 02 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;실제로 읽히는 제품 업데이트 이메일은 그것이 알리는 바로 그것을 정확히 요청했던 사람에게 보내진 것이다. 나머지 모든 것은 받은 편지함의 나머지와 흥미로움을 두고 경쟁하며, 릴리스 발표는 대부분의 주에 이 경쟁에서 진다. 이 하나의 사실이 어떤 문구보다 먼저 이메일의 형태를 결정해야 한다. 누가 그것을 받는지, 그리고 그 사람이 목록에 오르기 위해 무엇을 했는지.&lt;/p&gt;
&lt;h2&gt;제품 업데이트 이메일이란 무엇인가&lt;/h2&gt;
&lt;p&gt;기존 사용자에게 이미 사용 중인 제품에서 무엇이 바뀌었는지 알려주는 메시지다. 네 가지 서로 다른 유형이 있으며, 이들을 하나의 목록으로 취급하는 것이 오픈율이 떨어지는 이유다. 각각 다른 트리거, 다른 독자층, 다른 허용 가능한 빈도를 가진다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;유형&lt;/th&gt;
&lt;th&gt;트리거&lt;/th&gt;
&lt;th&gt;독자층&lt;/th&gt;
&lt;th&gt;빈도&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;타겟 알림&lt;/td&gt;
&lt;td&gt;누군가의 구체적인 요청이 출시됨&lt;/td&gt;
&lt;td&gt;한 사람&lt;/td&gt;
&lt;td&gt;발생할 때마다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;파괴적 변경 알림&lt;/td&gt;
&lt;td&gt;독자에게 작업을 강요하는 변경&lt;/td&gt;
&lt;td&gt;영향받는 계정만&lt;/td&gt;
&lt;td&gt;발생할 때마다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;다이제스트&lt;/td&gt;
&lt;td&gt;시간의 경과&lt;/td&gt;
&lt;td&gt;옵트인한 사용자&lt;/td&gt;
&lt;td&gt;최대 월 1회&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;출시 발표&lt;/td&gt;
&lt;td&gt;방해할 가치가 있는 출시&lt;/td&gt;
&lt;td&gt;세그먼트 또는 전체&lt;/td&gt;
&lt;td&gt;드물게, 드물게 느껴져야 함&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;대부분의 팀은 세 번째 유형만 만들고, 모두에게 보내고, 제품 업데이트 이메일이 효과가 없다고 결론짓는다. 처음 두 유형이 거의 모든 가치를 담고 있다. 독자에게는 이미 관심을 가질 이전의 이유가 있고, 메시지는 그 이유가 아직 살아 있는 동안 도착하기 때문이다.&lt;/p&gt;
&lt;p&gt;여기 나온 네 줄은 모두 고객을 위해 쓰여 있다. 영업팀, 지원팀, 고객 성공팀도 무엇이 출시됐는지 알아야 하며, 보통 이 넷과는 다른 형태로 알아야 한다; &lt;a href=&quot;https://changeloop.dev/blog/ko/internal-release-notes/&quot;&gt;내부용 릴리스 노트&lt;/a&gt;가 그 문서가 무엇을 말해야 하는지와, 왜 고객용 노트보다 먼저 나가야 하는지를 다룬다.&lt;/p&gt;
&lt;p&gt;이메일은 출시 발표가 사용할 수 있는 여러 채널 중 하나일 뿐, 유일한 것이 아니다. &lt;a href=&quot;https://changeloop.dev/blog/ko/new-feature-announcement/&quot;&gt;새 기능을 어떻게 발표해야 하는가&lt;/a&gt;가 나머지 채널과, 기능이 실제로 얼마나 큰지에 따라 그 사이에서 어떻게 선택하는지를 다룬다.&lt;/p&gt;
&lt;h2&gt;템플릿에는 무엇이 들어가야 하는가&lt;/h2&gt;
&lt;p&gt;이 순서로 여섯 개의 블록이 있다. 첫 번째가 보통 빠져 있는 것이며, 실제로 일을 해내는 것이다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;제목:  &amp;lt;무엇이 바뀌었는지, 독자의 언어로&amp;gt;

1. 왜 이것을 받는가
   &amp;quot;귀하는 3월에 CSV 내보내기를 요청하셨습니다.&amp;quot; 또는
   &amp;quot;귀하의 통합은 1월 15일에 변경되는 /v1/invoices를 호출하고
   있습니다.&amp;quot;

2. 무엇이 바뀌었는가
   한 문장으로. 이제 무엇이 가능한지, 또는 이제 무엇이 깨지는지.

3. 무엇을 해야 하는가
   흔히 &amp;quot;아무것도 없음&amp;quot;. 암시로 남기지 말고 명시적으로 말하라.

4. 어디서 볼 수 있는가
   홈페이지가 아니라 체인지로그 항목으로의 링크.

5. 언제
   출시된 날짜, 또는 언제부터 적용되는지.

6. 어떻게 구독을 취소하는가
   클릭 한 번, 즉시 존중됨.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;블록 1은 메시지와 일괄 발송의 차이다. 첫 문장에서 이것이 자신이 개인적으로 요청했던 것의 해결이라는 말을 듣는 독자는 나머지를 읽는다. 그것이 없으면 블록 2에서 5까지는 아무리 잘 쓰였어도 뉴스레터일 뿐이다.&lt;/p&gt;
&lt;p&gt;전체를 약 150단어 이하로 유지하라. 이메일은 체인지로그 항목을 가리키는 포인터이며, 세부 사항이 속한 곳은 그쪽이다. 항목 전체를 재현하는 이메일은 독자에게 클릭할 이유를 주지 않고, 여러분에게는 누군가가 신경 썼는지에 대한 신호도 주지 않는다.&lt;/p&gt;
&lt;h2&gt;어떤 제목이 효과가 있는가&lt;/h2&gt;
&lt;p&gt;릴리스가 아니라 변경 사항을 명명하라. &amp;quot;CSV 내보내기가 라이브됨&amp;quot;은 &amp;quot;9월 업데이트&amp;quot;를 이긴다. 전자는 독자가 평가할 수 있는 사실이고 후자는 그릇에 불과하기 때문이다. 제목의 버전 번호는 API 호출자에게는 유용하고 나머지 모두에게는 잡음이며, 독자층을 나누어야 할 또 다른 이유다.&lt;/p&gt;
&lt;p&gt;독자가 동의하지 않은 이점을 주장하는 것을 피하라. &amp;quot;귀하의 리포트가 이제 더 빨라졌습니다&amp;quot;는 그의 경험에 대해 무언가를 주장한다. &amp;quot;10,000행이 넘는 리포트가 이제 1초 이내에 로드됩니다&amp;quot;는 변경 사항을 보고하고 그것이 중요한지는 그가 결정하게 한다.&lt;/p&gt;
&lt;h2&gt;언제, 누구에게 보내야 하는가&lt;/h2&gt;
&lt;p&gt;그것이 출시되는 순간, 그것을 요청했던 사람들에게 개별적으로 타겟 알림을 보내라. 날짜가 확정되는 즉시, 그리고 그에 가까워질 때 다시 한번, 전체 목록이 아니라 실제로 영향받는 계정에 파괴적 변경 알림을 보내라. 그렇지 않으면 독자가 무언가를 놓칠 만큼 충분한 변경 사항이 있을 때만 다이제스트를 보내고, 사람들이 별도로 등록하게 하라.&lt;/p&gt;
&lt;p&gt;거의 절대 사용하지 말아야 할 목록은 &amp;quot;모든 사용자&amp;quot;다. 구체적인 메시지를 일반적인 메시지로 바꾸고, 구독 취소를 훈련시킨다. 이미 저장하고 있는 행동으로 세그먼트하라. 누가 요청했는지, 누가 이 엔드포인트를 사용하는지, 누가 이 플랜에 있는지.&lt;/p&gt;
&lt;h2&gt;이것을 보내는 데 동의가 필요한가&lt;/h2&gt;
&lt;p&gt;기존 고객에게는 이미 사용 중인 서비스에 대한 업데이트가 보통 잠재 고객에 대한 마케팅과는 다른 법적 문제이며, 답은 그들이 어디에 있는지와 가입 시 무엇을 알려주었는지에 달려 있다. EU에서는 &lt;a href=&quot;https://gdpr-info.eu/art-6-gdpr/&quot;&gt;GDPR 제6조&lt;/a&gt;의 어떤 법적 근거가 적용되는지가 관련 질문이며, 미국에서는 상업적 메시지가 &lt;a href=&quot;https://www.ftc.gov/business-guidance/resources/can-spam-act-compliance-guide-business&quot;&gt;FTC의 CAN-SPAM 준수 가이드&lt;/a&gt;에 명시된 구체적인 요건을 가진다. 둘 다 실질적으로 같은 것을 요구한다. 여러분이 누구인지 밝히고, 목적을 명확히 하고, 사람들이 멈출 수 있게 하라.&lt;/p&gt;
&lt;p&gt;근거가 무엇이든, 거래성 흐름과 마케팅 흐름을 발송 수준에서 분리하라. 프로모션 다이제스트와 목록을 공유했다는 이유로 고객이 구독을 취소한 파괴적 변경 알림은 그 날짜를 기다리는 지원 사고다.&lt;/p&gt;
&lt;h2&gt;실제로 채워 넣으면 어떤 모습인가&lt;/h2&gt;
&lt;p&gt;타겟 알림, 가장 가치 있는 제품 업데이트 이메일이자 대부분의 팀이 절대 만들지 않는 것이다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;제목: CSV 내보내기가 라이브됨

안녕하세요 Dana님,

3월에 CSV 내보내기를 요청하셨죠.

오늘 아침 라이브되었습니다. 리포트에는 이제 필터를 포함한
현재 뷰의 CSV를 생성하는 내보내기 버튼이 있습니다.

귀하 쪽에서 할 일은 없습니다. 이미 귀하의 계정에서 활성화되어
있습니다.

  세부 정보: example.com/changelog#csv-export
  출시일: 2026년 9월 2일

이것을 요청하셨기 때문에 받으셨습니다. 요청 업데이트에서
구독 취소: &amp;lt;링크&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;90단어이며, 독자는 첫 문장에서 왜 이것이 도착했는지 안다. 이것을 월간 다이제스트에서 아홉 개 항목 중 하나로 나타나는 같은 변경 사항과 비교해 보라. Dana에게는 자신의 요청이 나갔다는 것을 알아챌 이유가 없다.&lt;/p&gt;
&lt;h2&gt;무엇을 측정해야 하는가&lt;/h2&gt;
&lt;p&gt;오픈율만이 아니다. 타겟 알림의 경우 질문은 요청했던 사람이 돌아와서 그것을 사용했는지이며, 따라서 추적해야 할 숫자는 항목으로의 클릭과 그 계정이 일주일 안에 기능을 사용하는지 여부다. 파괴적 변경 알림의 경우 커버리지다. 영향받는 계정 중 몇 퍼센트가 날짜 전에 열었는지, 그리고 누구와 개별적으로 후속 조치를 했는지.&lt;/p&gt;
&lt;p&gt;다이제스트는 넷 중에서 오픈율이 많은 것을 의미하는 유일한 것이며, 그곳에서도 업계 벤치마크보다는 자체 기록에 대한 추세로서 더 유용하다. 서로 다른 유형의 제품 업데이트 이메일은 서로 다른 임무를 가지므로, 모두에 걸쳐 평균화된 숫자는 행동할 수 있는 무엇도 설명하지 못한다.&lt;/p&gt;
&lt;h2&gt;릴리스 노트와는 어떻게 다른가&lt;/h2&gt;
&lt;p&gt;릴리스 노트는 계속 사용 가능한 상태로 남는 문서다. 이메일은 한 번 일어나는 전달 메커니즘이다. 같은 변경 사항이 둘 다를 만들어내며, 이메일은 그것이 가리키는 항목보다 짧아야 한다. &lt;a href=&quot;https://changeloop.dev/blog/ko/release-notes-best-practices/&quot;&gt;릴리스 노트 모범 사례&lt;/a&gt;는 문서를 다루고, &lt;a href=&quot;https://changeloop.dev/blog/ko/changelog-vs-release-notes/&quot;&gt;체인지로그 대 릴리스 노트&lt;/a&gt;는 여러분이 지금 쓰고 있는 것이 무엇인지를 다룬다.&lt;/p&gt;
&lt;p&gt;제대로 정립할 가치가 있는 관계는 이렇다. 체인지로그 항목이 정본 텍스트이고 이메일은 그것을 인용한다. 이 둘이 어긋나면 클릭한 독자는 변경 사항에 대한 다른 설명을 발견하고 둘 다에 대한 신뢰를 잃는다. 항목을 먼저 발행하고 거기서 이메일을 생성하면 구조적으로 그 어긋남이 제거된다. changeloop도 자기 쪽에서 같은 방식으로 동작한다. 항목은 한 번 검토되어 &lt;a href=&quot;https://changeloop.dev/docs&quot;&gt;페이지, 피드, 위젯&lt;/a&gt;에 발행되며, 위젯을 통해 그것을 요청한 사람은 자신의 피드백으로 만들어진 GitHub 이슈와 위젯 자체에서 통보받는다. changeloop는 이메일을 보내지 않는다. 여러분의 이메일 도구가 발행된 항목을 인용한다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;제품 업데이트 이메일은 얼마나 자주 나가야 하는가?&lt;/strong&gt;
수신자가 알고 싶어 하는 구체적인 무언가가 있을 때마다이며, 타겟 알림의 경우 그의 요청이 출시될 때마다를, 다이제스트의 경우 최대 월 1회를 의미한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;이메일에 체인지로그 항목 전체가 들어가야 하는가?&lt;/strong&gt;
아니다. 한 문장과 링크면 된다. 항목이 정본 버전이며, 이메일 안의 전체 사본은 서로 맞춰야 할 두 개의 텍스트를 의미한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;어떤 오픈율을 기대해야 하는가?&lt;/strong&gt;
각 유형을 벤치마크가 아니라 그 자체와 비교하라. 타겟 알림과 월간 다이제스트는 서로 다른 제품이며, 그것들을 평균 내면 추적할 가치가 있는 유일한 숫자가 가려진다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;파괴적 변경을 위한 별도의 목록이 필요한가?&lt;/strong&gt;
그렇다. 그리고 그것은 사람들이 결과를 이해하지 못한 채 무심코 구독을 취소할 수 없는 목록이어야 한다. 그것이야말로 그들에게 장애를 초래하는 목록이기 때문이다.&lt;/p&gt;
</content:encoded></item><item><title>개발자를 잃지 않고 API를 비추천 처리하는 방법</title><link>https://changeloop.dev/blog/ko/api-deprecation/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/api-deprecation/</guid><description>비추천 처리는 날짜가 적힌 하나의 약속이다. 일정, 공지 템플릿, 응답 헤더, 서비스 종료가 사고로 번지지 않게 막는 한 단계를 설명한다.</description><pubDate>Sat, 29 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;API를 비추천 처리한다는 것은, 무언가가 오늘은 여전히 작동하지만 정해진 날짜에 작동을 멈춘다고 알리고, 그 약속의 두 절반을 모두 지키는 것을 뜻한다. 대부분의 비추천 처리는 두 번째 절반에서 실패한다. 날짜가 조용히 미뤄지거나, 그 날짜가 오는데 공지를 한 번도 보지 못한 호출자가 오류를 통해 알게 된다. 비추천 처리가 끝나는 것은 영향을 받은 모든 호출자가 이전을 마쳤거나, 아직 하지 않았다는 사실을 개별적으로 전달받았을 때다.&lt;/p&gt;
&lt;h2&gt;API 비추천 처리란 무엇인가&lt;/h2&gt;
&lt;p&gt;비추천 처리는 엔드포인트, 필드, 버전이 사라진다고 알리는 것과 실제로 제거하는 것 사이의 기간이다. 그 기간 동안 예전 동작은 계속 작동하고, 문서는 그것이 사라질 것이라고 말하며, 모든 응답은 기계가 읽을 수 있는 경고를 담는다. 제거는 별개의, 더 나중에 일어나는 사건이며, 흔히 서비스 종료라고 불린다. 이 둘은 자주 혼동되며, 바로 그 혼동이 피해를 만든다. &amp;quot;비추천&amp;quot;이 &amp;quot;이미 사라졌을 수도 있다&amp;quot;를 의미하기 시작하면, 호출자는 두 단어 모두를 더 이상 신뢰하지 않게 된다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;용어&lt;/th&gt;
&lt;th&gt;의미&lt;/th&gt;
&lt;th&gt;호출자가 믿고 의지할 수 있는 것&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;비추천됨&lt;/td&gt;
&lt;td&gt;사라질 것이라 발표되었으나 여전히 작동&lt;/td&gt;
&lt;td&gt;서비스 종료일까지의 완전한 동작&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;서비스 종료&lt;/td&gt;
&lt;td&gt;작동을 멈추는 날짜&lt;/td&gt;
&lt;td&gt;이 날짜 이후로는 아무것도 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;은퇴 / 제거됨&lt;/td&gt;
&lt;td&gt;사라짐. 요청이 실패한다&lt;/td&gt;
&lt;td&gt;오류, 이상적으로는 대체재를 이름으로 밝힌 오류&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;레거시&lt;/td&gt;
&lt;td&gt;정의되지 않음. 이 단어는 피하라&lt;/td&gt;
&lt;td&gt;아무것도 없음, 그것이 문제다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;비추천 처리 기간은 얼마나 되어야 하는가&lt;/h2&gt;
&lt;p&gt;호출자가 그것을 알아채고 작업을 처리할 수 있을 만큼 충분히 길어야 하며, 여러분이 그것을 쓴 시점이 아니라 공지가 실제로 그들에게 도달한 시점부터 재야 한다. 90일이 공개 웹 API의 흔한 최소치다. 최종 사용자가 설치하는 소프트웨어에 내장된 것이라면 12개월이 보통이다. 그 수정이 사용자의 릴리스 과정을 통해서도 출시되어야 하기 때문이다. Google의 버저닝 가이드인 &lt;a href=&quot;https://google.aip.dev/185&quot;&gt;AIP-185&lt;/a&gt;는 합리적인 전환 기간을 요구하고 베타 기능을 제거할 때조차 180일을 권장하며, Kubernetes는 자체 &lt;a href=&quot;https://kubernetes.io/docs/reference/using-api/deprecation-policy/&quot;&gt;비추천 처리 정책&lt;/a&gt;을 개월 수가 아니라 릴리스 횟수로 문서화한다. 이는 호출자가 버전별로 업그레이드할 때 올바른 단위다.&lt;/p&gt;
&lt;p&gt;기간을 하나 정해, 그것을 정책으로 문서에 적어두고, 변경마다 다시 결정하는 것을 멈춰라. 공표된 정책은 모든 비추천 처리를 협상에서 규칙의 적용으로 바꾼다.&lt;/p&gt;
&lt;p&gt;비추천 처리 정책을 문서로 적어두는 것은 창의 시작을 다룬다. &lt;a href=&quot;https://changeloop.dev/blog/ko/sunsetting-api-version/&quot;&gt;API 버전 종료하기&lt;/a&gt;는
기간이 실제로 다 되어 버전이 작동을 멈출 때 마지막에 필요한 별개의 공지를 다룬다.&lt;/p&gt;
&lt;h2&gt;비추천 처리 일정&lt;/h2&gt;
&lt;p&gt;첫날에 함께 발표되는 네 개의 날짜. 각각은 그것이 도래할 때 별개의 체인지로그 항목이 되므로, 체인지로그만 읽는 사람에게는 그 이야기가 네 번 전해진다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;발표한다.&lt;/strong&gt; 항목은 무엇이 비추천되는지, 왜인지, 무엇으로 대체되는지, 그리고 서비스 종료일을 말한다. 예전 기능에 대한 문서는 이전 경로를 링크하는 배너를 얻는다. 응답은 아래 설명되는 헤더를 얻는다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;중간 지점에서 상기시킨다.&lt;/strong&gt; 두 번째 항목과 함께, 여전히 예전 동작을 사용하고 있는 모든 호출자에게 직접 메시지를 보낸다. 이것은 사용량 데이터가 필요한 단계다. 누가 아직도 비추천된 엔드포인트를 호출하고 있는지 나열할 수 없다면 이 단계를 할 수 없으며, 그것은 다음 비추천 처리 전에 고쳐둘 가치가 있다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;날짜 직전에 잠시 차단한다.&lt;/strong&gt; 짧은 시간, 한 시간이나 하루 동안 예전 동작에 오류를 반환한 다음 복원한다. 모든 공지를 놓친 호출자는 아직 시간이 남아 있는 지금 그것을 알게 된다. GitHub는 &lt;a href=&quot;https://github.blog/2020-07-30-token-authentication-requirements-for-api-and-git-operations/&quot;&gt;API의 비밀번호 인증을 은퇴시키기&lt;/a&gt; 전에 예정된 브라운아웃을 사용했으며, 이것은 이 목록에서 가장 효과적인 단일 단계다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;서비스 종료.&lt;/strong&gt; 제거한다. 그것을 대체하는 오류는 대체재를 이름으로 밝히고 이전 가이드를 링크한다. 그 오류를 오랫동안 유지하라. 404는 호출자에게 아무것도 말해주지 않는다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;비추천 처리 공지는 무엇을 말해야 하는가&lt;/h2&gt;
&lt;p&gt;비추천 처리 공지는 무엇이 사라지는지, 언제 멈추는지, 대신 무엇을 써야 하는지, 그리고 누가 영향을 받는지를 말한다. 그 형태를 채운 예시는 다음과 같다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;GET /v1/reports/daily&lt;/code&gt;는 비추천되었으며 2027년 3월 1일에 작동을 멈춥니다.&lt;/strong&gt;
안정된 스키마와 페이지네이션으로 같은 데이터를 반환하는 &lt;code&gt;GET /v2/reports?granularity=day&lt;/code&gt;로 대체됩니다. 지난 30일 동안 v1 엔드포인트를 호출한 214개의 연동에 영향을 줍니다. 여러분의 것이 그중 하나라면 이 공지를 이메일로도 받게 됩니다. 이전 가이드: [링크]. 2027년 3월 1일까지는 아무것도 바뀌지 않습니다. 그 날짜부터 v1 엔드포인트는 이 항목으로의 링크와 함께 &lt;code&gt;410 Gone&lt;/code&gt;을 반환합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;모든 문장이 독자가 필요로 하는 무언가를 담고 있다. 영향받는 연동의 수는 각 독자에게 계속 읽어야 할지를 알려준다. &amp;quot;까지는 아무것도 바뀌지 않습니다&amp;quot;는 영향을 받지 않는 사람들이 탭을 닫게 해주는 문장이다. &lt;a href=&quot;https://changeloop.dev/changelog-examples&quot;&gt;체인지로그 예시&lt;/a&gt; 페이지는 이 형식을 일관되게 쓰는 팀들의 항목을 모아 놓았으며, 자신의 첫 항목을 쓰기 전에 그중 세 개를 읽어볼 가치가 있다.&lt;/p&gt;
&lt;h2&gt;비추천된 엔드포인트는 어떤 헤더를 보내야 하는가&lt;/h2&gt;
&lt;p&gt;발표일부터, 비추천된 엔드포인트로부터 오는 모든 응답에 &lt;code&gt;Deprecation&lt;/code&gt;, &lt;code&gt;Sunset&lt;/code&gt;, 그리고 후속으로의 &lt;code&gt;Link&lt;/code&gt;를 보내라. &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc9745&quot;&gt;&lt;code&gt;Deprecation&lt;/code&gt; 헤더&lt;/a&gt;는 비추천 처리가 발효된 날짜를 담고, &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc8594&quot;&gt;&lt;code&gt;Sunset&lt;/code&gt; 헤더&lt;/a&gt;는 엔드포인트가 응답을 멈추는 날짜를 담으며, &lt;code&gt;Link: &amp;lt;url&amp;gt;; rel=&amp;quot;successor-version&amp;quot;&lt;/code&gt;은 대신 무엇을 써야 하는지를 가리킨다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP/1.1 200 OK
Deprecation: @1756425600
Sunset: Mon, 01 Mar 2027 00:00:00 GMT
Link: &amp;lt;https://api.example.com/v2/reports&amp;gt;; rel=&amp;quot;successor-version&amp;quot;
Link: &amp;lt;https://example.com/changelog/daily-reports&amp;gt;; rel=&amp;quot;deprecation&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;대부분의 호출자는 그 헤더를 직접 읽지 않을 것이다. 그 가치는 호출자의 HTTP 클라이언트, 게이트웨이, 모니터링이 그것을 읽을 수 있다는 데 있으며, 그것이 여러분의 비추천 처리를 여러분 쪽의 페이지가 아니라 그들 쪽의 경보로 바꾼다. 여러분이 배포하는 SDK는 그것을 볼 때 경고를 로그로 남겨야 한다.&lt;/p&gt;
&lt;h2&gt;누가 통보받았고, 그것을 어떻게 아는가&lt;/h2&gt;
&lt;p&gt;이것은 서비스 종료가 조용히 지나갈지 지원 문의로 이어질지를 결정하는 단계이며, 체인지로그만으로는 하기 가장 어려운 단계다. 체인지로그 항목은 체인지로그를 읽는 모든 사람에게 알린다. 비추천 처리는 코드가 실제로 실패할 특정 사람들에게 도달해야 하며, 그들을 찾아내는 일반적인 방법은 중간 지점 리마인더가 필요로 하는 것과 같은 사용량 데이터다. 즉, 최근 비추천된 동작을 호출한 API 키, 앱, 계정이다.&lt;/p&gt;
&lt;p&gt;우리가 운영하는 루프는 이렇다. 항목은 비추천 처리를 추가하는 pull request로부터 초안이 작성되고, 사람이 문구와 날짜를 검토하며, 발행되고 나면 그 항목 자체가 통지가 된다. 그 문제에 대한 위젯 피드백이나 대체재 요청이 pull request가 닫는 GitHub issue가 된 사람은 누구든, 그것이 출시되었다는 코멘트를 그 issue에서 받으며, 그 항목으로의 링크가 함께 온다. &lt;a href=&quot;https://changeloop.dev/docs&quot;&gt;피드와 위젯&lt;/a&gt;은 나머지 모든 사람에게 같은 항목을 제공한다. &lt;a href=&quot;https://changeloop.dev/blog/ko/api-changelog/&quot;&gt;API 체인지로그&lt;/a&gt;의
다른 모든 항목과 함께다. 우리가 하지 않는 것은 사람이 발행하기 전에 비추천 처리를 &amp;quot;출시됨&amp;quot;으로 만드는 것이다. 잘못된 날짜가 적힌 공지는 공지가 없는 것보다 나쁘다.&lt;/p&gt;
&lt;p&gt;여러분의 도구가 무엇이든, 서비스 종료일에 답할 수 있어야 하는 질문은 이것이다. 지난주까지 누가 이것을 여전히 쓰고 있었으며, 그중 누구에게 직접 알렸는가. 답이 &amp;quot;그것에 대해 게시했다&amp;quot;라면, 그 서비스 종료는 아직 준비되지 않은 것이다.&lt;/p&gt;
&lt;h2&gt;비추천 처리와 버저닝의 차이는 무엇인가&lt;/h2&gt;
&lt;p&gt;버저닝은 새로운 것이 존재하는 동안 예전 동작을 계속 이용 가능하게 유지하는 방법이고, 비추천 처리는 예전 것을 은퇴시키는 방법이다. 이전 버전에 대한 비추천 처리 정책이 없는 새 API 버전은 둘 다를 영원히 운영하겠다는 약속일 뿐이다. 버저닝 없는 비추천 처리는 지연이 붙은 &lt;a href=&quot;https://changeloop.dev/blog/ko/breaking-changes/&quot;&gt;파괴적 변경&lt;/a&gt;이다. 둘 다 필요하며, 버전은 그중 더 쉬운 절반이다. GraphQL은 이름을 붙일 가치가 있는 예외다: 보통 거기에는 올릴 버전 번호 자체가 없으며, &lt;a href=&quot;https://changeloop.dev/blog/ko/graphql-schema-deprecation/&quot;&gt;GraphQL 스키마 비추천 처리&lt;/a&gt;는 하나의 공유된 스키마가 대신 지시어로 필드를 은퇴시키는 법을 다룬다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;비추천된 엔드포인트는 예전과 정확히 똑같이 계속 작동해야 하는가?&lt;/strong&gt;
그렇다, 서비스 종료일까지는. 허용되는 유일한 변경은 추가된 헤더와, 막바지에 미리 알린 예정된 브라운아웃뿐이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;은퇴한 엔드포인트는 어떤 상태 코드를 반환해야 하는가?&lt;/strong&gt;
&lt;code&gt;410 Gone&lt;/code&gt;이며, 대체재와 체인지로그 항목을 가리키는 &lt;code&gt;Link&lt;/code&gt; 헤더와 본문을 함께 담는다. &lt;code&gt;404&lt;/code&gt;는 그 URL이 애초에 존재한 적 없다고 말하는 것이며, 그것은 거짓이고 도움이 되지 않는다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;비추천 처리 기간을 단축할 수 있는가?&lt;/strong&gt;
보안상의 이유로만 가능하다. 예전 동작이 악용 가능하다면 그렇다고 말하고, 기간을 단축하고, 체인지로그에 의존하는 대신 영향을 받는 모든 호출자에게 직접 알려라.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;필드도 비추천 처리해야 하는가, 아니면 엔드포인트 전체만 하면 되는가?&lt;/strong&gt;
필드, 파라미터, enum 값, 기본값, 헤더는 모두 같은 처리를 필요로 한다. 각각이 올바른 호출자를 망가뜨릴 수 있기 때문이다. 제거된 필드는 가장 흔한 비추천 처리이면서 가장 자주 빠뜨려지는 것이기도 하다.&lt;/p&gt;
</content:encoded></item><item><title>호출자를 위한 API 버저닝 모범 사례</title><link>https://changeloop.dev/blog/ko/api-versioning-best-practices/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/api-versioning-best-practices/</guid><description>부서지는 것만 버전으로 관리하고, 호출자가 볼 수 있는 곳에 버전을 두며, 예전 버전은 정해진 날짜까지 유지하자. 네 가지 방식을 비교한다.</description><pubDate>Sat, 29 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;API 버저닝이란 계약을 변경한 후에도 예전 계약을 계속 작동하게 유지하는 관행이며, 그럼으로써 호출자는 여러분의 일정이 아니라 자기 자신의 일정에 맞춰 이전할 수 있게 된다. 이 문장에는 중요한 두 가지 결정이 담겨 있다. 무엇을 계약의 변경으로 볼 것인가, 그리고 예전 것을 얼마나 오래 작동하게 유지할 것인가. 버전 번호가 어디에 있는가는, 많은 버저닝 논쟁의 중심에 있는 문제이지만, 셋 중 가장 덜 중요하며 가장 올바르게 처리하기 쉬운 부분이다.&lt;/p&gt;
&lt;h2&gt;API는 언제 버전으로 관리해야 하는가&lt;/h2&gt;
&lt;p&gt;변경이 올바른 호출자를 망가뜨릴 때만 API를 버전으로 관리하라. 추가적인 변경, 새 필드, 새 엔드포인트, 새 선택적 파라미터는 버전이 필요 없다. 예전 계약에 맞춰 작성된 호출자는 계속 작동하고, 새 기능은 그저 그곳에 존재할 뿐이기 때문이다. &lt;a href=&quot;https://changeloop.dev/blog/ko/breaking-changes/&quot;&gt;파괴적 변경&lt;/a&gt;은 버전이 필요하다. 대안은 호출자가 오류를 통해 그것을 알게 되는 것이기 때문이다. 추가적인 것들까지 포함해 모든 릴리스를 버전으로 관리하는 것은 호출자에게 버전이 소음이라고 가르치는 것이며, 그들은 정말로 중요한 공지를 더는 읽지 않게 된다.&lt;/p&gt;
&lt;p&gt;실용적인 테스트는 파괴적 변경 글에 있는 것과 같다. 문서화된 동작에만 의존했던 호출자가 계속 작동하기 위해 무언가를 바꿔야 한다면, 그 변경은 버전이 필요하다. 그렇지 않다면 현재 버전 아래서 출시하고 체인지로그 항목을 써라.&lt;/p&gt;
&lt;h2&gt;어떤 API 버저닝 방식을 써야 하는가&lt;/h2&gt;
&lt;p&gt;호출자가 가장 쉽게 보고 설정할 수 있는 방식을 써라. 대부분의 공개 API에서 그것은 URL 경로 안의 버전이거나 날짜가 붙은 버전 헤더다. 네 가지 흔한 방식은 능력보다는 호출자에게 무엇을 요구하는가에서 차이가 나며, 그것이 선택의 올바른 근거다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;방식&lt;/th&gt;
&lt;th&gt;예시&lt;/th&gt;
&lt;th&gt;호출자가 해야 할 일&lt;/th&gt;
&lt;th&gt;사용하는 곳&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;URL 경로&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/v2/invoices&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;이전할 때 URL을 바꾼다&lt;/td&gt;
&lt;td&gt;대부분의 공개 REST API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;버전 헤더&lt;/td&gt;
&lt;td&gt;&lt;code&gt;X-GitHub-Api-Version: 2022-11-28&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;헤더를 보내거나, 기본값을 받아들인다&lt;/td&gt;
&lt;td&gt;GitHub&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;날짜가 붙은 계정 버전&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Stripe-Version: 2026-08-26&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;요청마다, 또는 계정마다 날짜를 고정한다&lt;/td&gt;
&lt;td&gt;Stripe&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;쿼리 파라미터&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/invoices?version=2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;파라미터를 붙인다&lt;/td&gt;
&lt;td&gt;오래된 API. 오늘날 잘 선택되지 않는다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;미디어 타입&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Accept: application/vnd.example.v2+json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;콘텐츠 타입을 협상한다&lt;/td&gt;
&lt;td&gt;원칙주의자들. 관리할 수 있는 호출자는 적다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;URL 경로&lt;/strong&gt;는 가시성이 가장 높고 유연성이 가장 낮다. 모든 호출자는 로그 한 줄만 읽어도 자신이 어느 버전에 있는지 알 수 있고, 버전 올리기는 찾아 바꾸기로 끝난다. 대가는 전체 표면이 한 번에 움직인다는 것이다. 모든 엔드포인트에 새 버전을 발행하지 않고는 하나의 엔드포인트의 계약만 바꿀 수 없으므로, 경로 버전은 드물고 규모가 커지는 경향이 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;버전 헤더&lt;/strong&gt;는 URL을 안정적으로 유지하면서, 아무것도 보내지 않는 호출자를 위해 서버 쪽에서 기본값을 고를 수 있게 한다. 그것이 &lt;a href=&quot;https://docs.github.com/en/rest/about-the-rest-api/api-versions&quot;&gt;GitHub의 REST API 버전&lt;/a&gt;이 작동하는 방식이다. &lt;code&gt;X-GitHub-Api-Version&lt;/code&gt; 안의 날짜로 이름 붙은 버전이며, 지원되는 가장 오래된 버전이 기본값이 되어 버전을 지정하지 않은 호출자도 망가지지 않는다. 대가는 버전이 URL 안에서는 보이지 않으며 새 클라이언트에서 잊히기 쉽다는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;날짜가 붙은 계정 버전&lt;/strong&gt;은 헤더 방식에 한 가지를 더한 것이다. 버전이 계정에 묶여 저장되므로, 아무것도 보내지 않아도 모든 요청이 그것을 받는다. &lt;a href=&quot;https://docs.stripe.com/api/versioning&quot;&gt;Stripe의 버저닝&lt;/a&gt;은 각 계정을 생성 시점의 버전에 고정하고, 요청은 &lt;code&gt;Stripe-Version&lt;/code&gt;으로 그것을 덮어쓸 수 있다. 이것은 호출자에게 가장 친절한 방식이며, 운영하는 쪽에는 가장 손이 많이 가는 방식이다. 지원하는 모든 버전과 현재 버전 사이를 서버가 번역해야 하기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;쿼리 파라미터&lt;/strong&gt;와 &lt;strong&gt;미디어 타입&lt;/strong&gt;은 둘 다 작동하지만, 각자 다른 방식으로 가시성 테스트에 실패한다. 쿼리 파라미터는 URL을 조립할 때 빠뜨리기 쉽고, 미디어 타입 버전은 호출자가 디버깅에 쓰는 거의 모든 도구에서 보이지 않는다. Stripe의 날짜 기반 방식은 날짜 접근법의 가장 잘 알려진 예이며, &lt;a href=&quot;https://changeloop.dev/blog/ko/stripe-api-versioning/&quot;&gt;Stripe는 API 버전을 어떻게 관리하는가&lt;/a&gt;가 그 과정을 차근차근 보여준다.&lt;/p&gt;
&lt;h2&gt;실제로 API 버저닝은 어떻게 하는가&lt;/h2&gt;
&lt;p&gt;실제로 버전이란 이름 붙은 동작의 집합이며, 서버는 각 요청을 그중 하나에 대응시킨다. 어떤 방식이 이름을 운반하든 단계는 같다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;버전은 시맨틱 버전이 아니라 날짜나 정수로 이름 붙인다.&lt;/strong&gt; 웹 API는 패키지가 아니다. 호출자는 URL의 마이너 버전을 고정할 수 없으므로, &lt;code&gt;v2&lt;/code&gt;나 &lt;code&gt;2026-08-26&lt;/code&gt;은 호출자가 필요로 하는 모든 것을 전달하는 반면, &lt;a href=&quot;https://semver.org/&quot;&gt;시맨틱 버저닝&lt;/a&gt; 번호는 이 방식이 지킬 수 없는 호환성의 약속을 암시해버린다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;신경 쓸 필요가 없는 코드 경로에서 버전을 멀리 두어라.&lt;/strong&gt; 버전은 가장자리에서 변환 계층을 선택해야 하며, 비즈니스 로직을 분기시켜서는 안 된다. 코드베이스를 통째로 두 벌 갖는 것이 바로 버전이 관리되지 않는 채로 남는 방식이다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;모든 버전에 기본값과 문서를 부여하라.&lt;/strong&gt; 버전을 보내지 않는 호출자는 최신이 아니라 항상 지원되는 가장 오래된 버전을 받아야 한다. 그래야 고정하지 않은 클라이언트가 릴리스 당일에 망가지지 않는다. 각 버전에는 이전 버전에서 무엇이 바뀌었는지 말하는 페이지가 있다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;지원 기간을 정하고 그것을 공개하라.&lt;/strong&gt; Google의 버저닝 가이드인 &lt;a href=&quot;https://google.aip.dev/185&quot;&gt;AIP-185&lt;/a&gt;는 충분히 공지된 합리적인 전환 기간을 요구하며, 베타 기능에도 180일을 권장한다. 기간을 정해 문서로 남기고, 버전마다 재협상하지 않고 그것을 적용하라.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;버전을 엔드포인트와 같은 방식으로 은퇴시켜라.&lt;/strong&gt; 기간이 지난 버전은 여느 &lt;a href=&quot;https://changeloop.dev/blog/ko/api-deprecation/&quot;&gt;비추천된 API&lt;/a&gt;와 같은 대우를 받는다. 발표, 모든 응답에 붙는 &lt;code&gt;Sunset&lt;/code&gt; 헤더(&lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc8594&quot;&gt;RFC 8594&lt;/a&gt;), 아직 남아 있는 호출자에게 보내는 중간 리마인더, 그리고 지켜지는 제거일이다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;REST API에서 v1과 v2란 무엇인가&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;v1&lt;/code&gt;과 &lt;code&gt;v2&lt;/code&gt;는 같은 서버가 동시에 지원하는 두 계약의 이름이다. &lt;code&gt;v2&lt;/code&gt;가 존재하는 이유는 &lt;code&gt;v1&lt;/code&gt; 안의 무언가가 호출자를 망가뜨리지 않고는 바꿀 수 없었기 때문이며, 그 변경은 새 계약 안으로 들어갔고 예전 것은 계속 작동했다. 번호 그 자체는 &lt;code&gt;v2&lt;/code&gt;가 완성되었다거나 &lt;code&gt;v1&lt;/code&gt;이 죽었다는 것을 전혀 의미하지 않는다. 둘 다 문서가 그렇게 말할 때만 참이 된다. 분기마다 &lt;code&gt;v3&lt;/code&gt;가 나타난다면, 그것은 추가적인 변경이 버전으로 관리되고 있거나, 애초에 계약이 변화를 흡수하도록 설계되지 않았다는 신호다.&lt;/p&gt;
&lt;p&gt;이것은 URL 경로 버전 관리 모델이며, 버전 번호는 호출자가 다이얼하는 세그먼트다. gRPC
서비스는 보통 같은 문제를 다른 방식으로 해결한다. 버전은 &lt;code&gt;.proto&lt;/code&gt; 파일 자체 안의 패키지
이름에 산다. &lt;a href=&quot;https://changeloop.dev/blog/ko/grpc-protobuf-api-changes/&quot;&gt;gRPC와 Protobuf&lt;/a&gt;는 그 차이와, 그곳에서
와이어 호환성이 URL의 형태가 아니라 필드 번호로 정의되는 이유를 다룬다.&lt;/p&gt;
&lt;h2&gt;버전 변경은 무엇을 알려야 하는가&lt;/h2&gt;
&lt;p&gt;버전 변경은 무엇이 부서지는지, 누가 영향을 받는지, 어떻게 이전하는지, 그리고 예전 버전이 얼마나 오래 계속 작동하는지를 알려야 한다. 이 항목은 다른 파괴적 변경 항목과 같은 형태에 지원 기간을 말하는 한 줄을 더한 것이다. 다음은 헤더로 버전이 관리되는 API를 위한 예시다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;API 버전 2026-11-01을 사용할 수 있습니다. 버전 2025-06-15는 2027년 11월 1일까지 지원됩니다.&lt;/strong&gt;
2026-11-01의 새로운 점: &lt;code&gt;GET /invoices&lt;/code&gt;는 이제 &lt;code&gt;amount&lt;/code&gt;를 소수 형태의 문자열이 아니라 최소 단위의 정수로 반환합니다. 비추천되었던 &lt;code&gt;customer_name&lt;/code&gt; 필드는 제거되고 &lt;code&gt;customer&lt;/code&gt; 객체로 대체되었습니다. &lt;code&gt;amount&lt;/code&gt;를 문자열로 파싱하고 있는 2025-06-15 사용 호출자에게 영향을 줍니다. 이는 2025년 6월 이전에 생성된, 버전을 고정하지 않은 클라이언트의 기본값입니다. 이전 방법: &lt;code&gt;amount&lt;/code&gt;를 정수로 파싱하고, 이름은 &lt;code&gt;customer.name&lt;/code&gt;에서 읽으세요. 준비가 되면 &lt;code&gt;X-Api-Version: 2026-11-01&lt;/code&gt;을 고정하세요. 버전을 고정하지 않은 호출자에게는 아무것도 바뀌지 않습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;마지막 문장이 대부분의 독자를 그 자리에서 읽기를 멈추게 해주는 문장이며, 모든 버전 발표에 포함되어야 한다. &lt;a href=&quot;https://changeloop.dev/changelog-examples&quot;&gt;체인지로그 예시&lt;/a&gt; 페이지는 이런 방식으로 버전을 관리하는 API들의 항목을 모아두었으며, 좋은 것들과 그렇지 않은 것들의 차이는 대개 이 마지막 한 줄에 있다.&lt;/p&gt;
&lt;h2&gt;버전이 바뀌면 누가 통보받는가&lt;/h2&gt;
&lt;p&gt;예전 버전에 있는 모든 사람에게는 개별적으로, 그 외 모든 사람에게는 체인지로그로. 버전 변경은 &amp;quot;게시해뒀다&amp;quot;가 반드시 중요한 호출자를 놓치게 되는 경우다. 즉, 2년 전에 버전을 고정한 이후 릴리스 노트를 한 번도 읽지 않은 사람들이다. 사용량 데이터가 그들이 누구인지 답해준다. 통지는 그들의 코드가 있는 곳, 즉 응답 헤더와 계정 소유자에게 보내는 메시지에 도달해야 한다.&lt;/p&gt;
&lt;p&gt;우리가 운영하는 루프에서는, 버전을 알리는 항목이 그것을 출시하는 pull request로부터 초안이 작성되고, 사람이 검토하며, &lt;a href=&quot;https://changeloop.dev/docs&quot;&gt;피드와 위젯&lt;/a&gt;에 발행되고, 그곳에서 버전이 관리되는 클라이언트가 그것을 JSON으로 읽을 수 있다. 그 변경을 요청했거나 그것이 고치는 버그를 신고한 위젯 피드백이 pull request가 닫는 GitHub issue가 된 사람은 누구든, 항목이 발행될 때 그 issue에서 통보받는다. 그 메커니즘은 어떤 항목이든 같으며, 버전 올리기는 그저 가장 영향이 큰 항목일 뿐이다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;모든 API 변경이 새 버전을 받아야 하는가?&lt;/strong&gt;
아니다. 파괴적 변경만이다. 추가적인 변경은 현재 버전 아래서 체인지로그 항목과 함께 출시된다. 추가적인 변경을 버전으로 관리하는 것은 호출자에게 버전을 무시하도록 가르친다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;URL 버저닝과 헤더 버저닝 중 어느 것이 더 나은가?&lt;/strong&gt;
URL 버저닝은 호출자가 보기에는 쉽고, 여러분이 조금씩 발전시키기는 어렵다. 헤더 버저닝은 그 반대다. 작은 클라이언트가 많은 공개 API에서는 URL 버저닝이 덜 실패한다. 변환 계층을 가진 대규모 API에서는 날짜가 붙은 헤더가 더 잘 확장된다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;동시에 몇 개의 버전을 지원해야 하는가?&lt;/strong&gt;
지원 기간이 허락하는 한 최소한으로, 결코 무제한으로는 안 된다. 두세 개의 동시 버전이 보통이며, 그것을 넘어서면 대개 버전이 은퇴되지 않고 있다는 뜻이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;버전을 지정하지 않은 요청은 무엇을 받아야 하는가?&lt;/strong&gt;
지원되는 가장 오래된 버전이다. 기존의 고정하지 않은 클라이언트가 계속 작동하도록 하기 위함이며, 어떤 버전을 받았는지 알려주는 응답 헤더와 함께 반환된다.&lt;/p&gt;
</content:encoded></item><item><title>파괴적 변경: 무엇이 해당하고 어떻게 출시하는가</title><link>https://changeloop.dev/blog/ko/breaking-changes/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/breaking-changes/</guid><description>파괴적 변경은 올바른 호출자가 버티지 못하는 변경이다. 해당 여부, CI에서 잡는 법, 안전하게 출시하는 방법을 정리한다.</description><pubDate>Sat, 29 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;파괴적 변경이란 올바르게 작성된 호출자가 버텨낼 수 없었던 변경이다. 이 정의가 중요한 이유는, 무언가가 &amp;quot;해당되는가&amp;quot;에 대한 대부분의 논쟁이 실제로는 누가 잘못 쥐고 있었는가에 대한 논쟁이기 때문이다. 호출자가 여러분의 문서를 따랐는데 여러분의 변경이 그 코드를 멈추게 만들었다면, 그 변경은 파괴적이었다. 여러분이 무엇을 의도했는지는 여기에 아무 상관이 없다.&lt;/p&gt;
&lt;p&gt;그것이 테스트의 전부다. 이 글의 나머지는 거기서 파생되는 것들이다. 무엇이 이 테스트에 실패하는가, 무엇이 통과하는가, 병합되기 전에 실패를 어떻게 잡는가, 그리고 파괴적 변경을 출시하고 있다는 것을 알았을 때 무엇을 해야 하는가.&lt;/p&gt;
&lt;h2&gt;무엇이 파괴적 변경에 해당하는가&lt;/h2&gt;
&lt;p&gt;diff가 아니라 호출자에게 테스트를 적용하라. 문서화된 동작에만 의존했던 호출자가 계속 작동하기 위해 코드, 설정, 또는 데이터를 바꿔야 한다면, 그 변경은 파괴적이다. 필드 제거, 엔드포인트 이름 변경, 검증 강화, 기본값 변경, 값의 타입 변경은 모두 여기에 해당한다. 선택적 필드를 추가하는 것은 해당하지 않는다. 버그 수정은 보통 해당하지 않지만, 아래에 중요한 예외가 하나 있다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;변경&lt;/th&gt;
&lt;th&gt;파괴적인가?&lt;/th&gt;
&lt;th&gt;이유&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;필드, 엔드포인트, 플래그, 옵션을 제거하거나 이름을 바꾼다&lt;/td&gt;
&lt;td&gt;그렇다&lt;/td&gt;
&lt;td&gt;올바른 호출자는 그것을 참조하고 있다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;선택적 필드나 새 엔드포인트를 추가한다&lt;/td&gt;
&lt;td&gt;아니다&lt;/td&gt;
&lt;td&gt;기존 호출은 바뀌지 않는다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;선택적 입력을 필수로 바꾼다&lt;/td&gt;
&lt;td&gt;그렇다&lt;/td&gt;
&lt;td&gt;그것을 생략했던 호출이 이제 실패한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;이전에는 받아들이던 검증을 강화한다&lt;/td&gt;
&lt;td&gt;그렇다&lt;/td&gt;
&lt;td&gt;작동했던 입력이 이제 거부된다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;기본값을 바꾼다&lt;/td&gt;
&lt;td&gt;그렇다&lt;/td&gt;
&lt;td&gt;그것을 설정하지 않았던 호출자가 새 동작을 받는다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;타입을 바꾼다(문자열에서 숫자로, 단일 값에서 배열로)&lt;/td&gt;
&lt;td&gt;그렇다&lt;/td&gt;
&lt;td&gt;문서화된 타입에 맞춰 쓰인 파서가 실패한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;객체의 키 순서를 바꾼다&lt;/td&gt;
&lt;td&gt;아니다&lt;/td&gt;
&lt;td&gt;순서를 문서화하지 않은 한&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;호출자가 의존하고 있던 버그를 수정한다&lt;/td&gt;
&lt;td&gt;실질적으로 그렇다&lt;/td&gt;
&lt;td&gt;우발적 계약에 관한 절 참고&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;요청 한도나 크기 상한을 올린다&lt;/td&gt;
&lt;td&gt;아니다&lt;/td&gt;
&lt;td&gt;작동하던 것 중 멈추는 것은 없다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;요청 한도나 크기 상한을 낮춘다&lt;/td&gt;
&lt;td&gt;그렇다&lt;/td&gt;
&lt;td&gt;문제없던 트래픽이 이제 제한된다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;오류 메시지의 문구를 바꾼다&lt;/td&gt;
&lt;td&gt;상황에 따라 다르다&lt;/td&gt;
&lt;td&gt;문서화했거나 호출자가 그것을 매칭한다면 파괴적이다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;무엇이 파괴적 변경이 아닌가&lt;/h2&gt;
&lt;p&gt;이전에 작동하던 모든 호출이 그대로 작동하고 의미도 같다면, 그 변경은 파괴적이지 않다. 새 엔드포인트 추가, 선택적 요청 매개변수 추가, 응답에 필드 추가, 필수 입력을 선택적으로 바꾸기, 한도 올리기, 아무도 매칭하지 않는 오류 메시지 개선은 모두 테스트를 통과한다. 이런 추가적 변경은 일반적인 체인지로그 항목과 함께 마이너 릴리스로 출시할 수 있다.&lt;/p&gt;
&lt;p&gt;그래도 추가적 변경이 호출자를 망가뜨리는 경우가 세 가지 있다. 알 수 없는 필드를 거부하는 역직렬화기를 가진 클라이언트는 응답에 새 필드가 처음 생기는 순간 실패하므로, 호출자가 인식하지 못하는 필드는 무시해야 한다고 일찍부터 문서화하라. 새 enum 값은 모든 경우를 다 처리하는 switch문을 가진 모든 호출자를 망가뜨린다(아래에서 더 다룬다). 그리고 커진 응답은 호출자가 생각해본 적 없는 크기 제한, 타임아웃, 열 너비를 넘게 만들 수 있다.&lt;/p&gt;
&lt;p&gt;표의 네 행은 더 자세히 볼 가치가 있다. 그곳이 바로 의견이 갈리는 지점이기 때문이다.&lt;/p&gt;
&lt;h2&gt;팀들이 놓치는 네 가지 파괴적 변경&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;우발적 계약.&lt;/strong&gt; 여러분의 API가 삼 년 동안 같은 문서화되지 않은 필드를 반환해왔다면, 어떤 호출자는 그 위에 무언가를 쌓아올렸을 것이다. &lt;a href=&quot;https://www.hyrumslaw.com/&quot;&gt;Hyrum의 법칙&lt;/a&gt;이 짧은 버전이다. 사용자가 충분히 많다면, 여러분 시스템의 관찰 가능한 모든 동작에 누군가는 의존하게 된다. 이것이 &amp;quot;그것은 버그 수정이었다&amp;quot;가 변명이 되지 못하는 이유다. 그 수정은 옳을 수 있으면서도 여전히 파괴적일 수 있다. 그것을 파괴적 변경으로서 출시하라.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;스키마 변경 없는 동작 변경.&lt;/strong&gt; 필드는 여전히 그대로 있고, 타입도 같지만, 이제 값이 다른 것을 의미한다. 예전에는 &lt;code&gt;active&lt;/code&gt; 또는 &lt;code&gt;inactive&lt;/code&gt;였던 &lt;code&gt;status&lt;/code&gt;가 이제 &lt;code&gt;suspended&lt;/code&gt;도 반환하게 되면, 이는 모든 경우를 다 처리하는 switch문을 가진 모든 호출자를 망가뜨린다. 로컬 시간에서 UTC로 옮겨가는 타임스탬프는 문서를 두 번 읽지 않은 모든 사람을 망가뜨린다. OpenAPI 파일의 diff에는 이런 것들이 전혀 나타나지 않는다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;강화된 검증.&lt;/strong&gt; TLD가 없는 이메일, 끝에 붙은 공백, 80자를 넘는 이름을 거부하기 시작한다. 정확히 그것을 보내고 있던 모든 호출자는 지난주까지 작동하던 요청에 대해 이제 400을 받게 된다. 검증 변경은 &amp;quot;견고화&amp;quot; 수정으로 출시되는 가장 흔한 유형이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;바뀐 기본값.&lt;/strong&gt; 값을 명시적으로 설정한 사람은 아무도 눈치채지 못한다. 설정하지 않은 사람, 즉 대부분의 호출자는 한 줄도 바꾸지 않은 채 새 동작을 받게 된다. 바뀐 기본값이 사용자의 대다수를 망가뜨리는 이유는 정확히 그들이 그 설정을 본 적이 없기 때문이다.&lt;/p&gt;
&lt;h2&gt;출시 전에 파괴적 변경을 어떻게 탐지하는가&lt;/h2&gt;
&lt;p&gt;풀 리퀘스트의 계약을 main 브랜치의 계약과 CI에서 비교하고, 파괴적인 차이가 있으면 빌드를 실패시켜라. 대부분의 인터페이스 형식에는 스키마 diff 도구가 있고, 각 도구는 자기 형식의 파괴 규칙을 알고 있다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;인터페이스&lt;/th&gt;
&lt;th&gt;도구&lt;/th&gt;
&lt;th&gt;비교 대상&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;REST (OpenAPI)&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/oasdiff/oasdiff&quot;&gt;oasdiff&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;두 OpenAPI 명세, 파괴적 변경 보고서 포함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gRPC (Protobuf)&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://buf.build/docs/breaking/&quot;&gt;buf breaking&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.proto&lt;/code&gt; 파일, 와이어 또는 소스 수준&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GraphQL&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/kamilkisiela/graphql-inspector&quot;&gt;GraphQL Inspector&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;두 스키마, 파괴적이거나 위험한 변경을 표시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rust 크레이트&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/obi1kenobi/cargo-semver-checks&quot;&gt;cargo-semver-checks&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;공개 API와 마지막으로 게시된 버전&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TypeScript 패키지&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://api-extractor.com/&quot;&gt;API Extractor&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;패키지 공개 API의 커밋된 보고서&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;이 도구들은 제거된 필드, 이름이 바뀐 연산, 바뀐 타입을 안정적으로 잡아낸다. 하지만 위의 네 가지 중 처음 두 가지, 즉 우발적 계약과 동작 변경은 스키마에 나타나지 않으므로 볼 수 없다. 뻔한 것들은 도구로 막고, 나머지는 &amp;quot;올바른 호출자가 이것을 알아차릴 수 있는가?&amp;quot;라는 리뷰 질문으로 막아라. 같은 CI 작업은 체인지로그 항목을 요구하기에도 자연스러운 자리이며, 이는 &lt;a href=&quot;https://changeloop.dev/blog/ko/changelog-ci-enforcement/&quot;&gt;CI에서 체인지로그 항목 강제하기&lt;/a&gt;에서 설명한다. 와이어 수준의 사례는 &lt;a href=&quot;https://changeloop.dev/blog/ko/grpc-protobuf-api-changes/&quot;&gt;gRPC와 Protobuf API 변경&lt;/a&gt;에서 다룬다.&lt;/p&gt;
&lt;h2&gt;커밋에서 파괴적 변경을 어떻게 표시하는가&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.conventionalcommits.org/en/v1.0.0/&quot;&gt;Conventional Commits&lt;/a&gt;에서 파괴적 변경은 콜론 앞의 &lt;code&gt;!&lt;/code&gt;(&lt;code&gt;feat(api)!: remove the legacy export endpoint&lt;/code&gt;) 또는 &lt;code&gt;BREAKING CHANGE:&lt;/code&gt;로 시작하고 설명이 이어지는 푸터로 표시한다. 어느 쪽이든 메이저 버전에 대응한다. 푸터는 체인지로그 항목의 초안으로 써라. 누가 영향을 받고 무엇을 해야 하는지를 밝히면 된다. 이 관례가 어디까지 도움이 되는지는 &lt;a href=&quot;https://changeloop.dev/blog/ko/conventional-commits-changelog/&quot;&gt;Conventional Commits와 체인지로그&lt;/a&gt;에서 다룬다.&lt;/p&gt;
&lt;p&gt;같은 규칙이 라이브러리에도 적용된다. 공개 함수의 제거, 매개변수 타입의 축소, 반환값의 변경은 시맨틱 버저닝에서 메이저 버전이다. 라이브러리가 항상 이를 따르는 것은 아니다. &lt;a href=&quot;https://arxiv.org/abs/2110.07889&quot;&gt;Maven Central 업그레이드 119,879건에 대한 연구&lt;/a&gt;에서는 16.6%가 시맨틱 버저닝을 어겼지만, 영향을 받은 클라이언트 프로젝트는 7.9%에 그쳤다. 그 변경의 대부분이 어떤 클라이언트도 호출하지 않는 코드를 건드렸기 때문이다. 파괴는 호출자에서 측정된다.&lt;/p&gt;
&lt;h2&gt;파괴적 변경은 어떻게 출시하는가&lt;/h2&gt;
&lt;p&gt;공개적으로, 날짜를 정해, 경로와 함께 출시하라. 아래 단계는 순서대로이며, 마지막 것이 대부분의 팀이 건너뛰는 단계다. 영향을 받은 사람들에게, 그들이 기다리고 있던 일이 이제 일어났다고 알리는 것이다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;그것인지 아닌지를 판단하라.&lt;/strong&gt; diff가 아니라 위의 테스트를 사용하라. 두 명의 엔지니어가 동의하지 않는다면, 그것은 파괴적이다. 그 불일치 자체가, 호출자가 예전 동작에 합리적으로 의존했을 수 있다는 증거다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;버전을 붙여라.&lt;/strong&gt; &lt;a href=&quot;https://semver.org/&quot;&gt;시맨틱 버저닝&lt;/a&gt; 아래에서 파괴적 변경은 메이저 버전이다. 날짜 기반이거나 버전이 붙은 API를 운영한다면, 그것은 새 버전에 들어가고 예전 것은 정해진 날짜까지 계속 작동한다. 버전을 붙일 수 없다면, 여러분은 파괴적 변경을 출시하는 것이 아니라 체인지로그 항목이 붙은 장애를 출시하는 것이다. 어떤 방식이 버전을 운반하는지는 &lt;a href=&quot;https://changeloop.dev/blog/ko/api-versioning-best-practices/&quot;&gt;API 버저닝 모범 사례&lt;/a&gt;의 주제다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;코드가 병합되기 전에 항목을 써라.&lt;/strong&gt; 그 항목은 고정된 형태를 가진다. 무엇이 바뀌는지, 누가 영향을 받는지, 무엇을 해야 하는지, 언제까지인지. 이 네 가지를 모두 채울 수 없다면, 그 변경은 아직 준비되지 않은 것이다. &lt;a href=&quot;https://changeloop.dev/release-notes-template&quot;&gt;릴리스 노트 템플릿&lt;/a&gt;이 바로 이런 이유로 이런 항목들을 버전 번호가 아니라 날짜와 함께 맨 앞에 둔다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;릴리스 번호가 아니라 기한을 제시하라.&lt;/strong&gt; &amp;quot;v5에서 제거됨&amp;quot;은 여러분의 릴리스를 추적하지 않는 사람에게는 아무 의미가 없다. &amp;quot;2026년 11월 1일부터 작동하지 않음&amp;quot;은 모든 사람에게 하나의 의미를 갖는다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;마이그레이션 방법을 제공하라.&lt;/strong&gt; 새 호출 옆에 예전 호출의 코드 샘플을 둔다. 변경이 이름 변경이라면 같은 문장 안에서 두 이름을 모두 말하라. 필드가 제거된 것이라면 그 데이터가 어디로 갔는지 말하라.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;예전 동작이 문서화되어 있던 모든 곳에서 알려라.&lt;/strong&gt; 체인지로그, 그 엔드포인트를 설명하는 문서 페이지, SDK의 릴리스 노트, 그리고 응답에 비추천 헤더가 있다면 그것까지. 한 곳에서만 알리는 것은 우연히 그곳을 본 사람들에게만 알리는 것이다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;루프를 닫아라.&lt;/strong&gt; 고객이 그 변경을 요청했거나, 그것으로 이어진 버그를 신고했다면, 그것이 출시될 때 알려라. 이것이 그것을 사용자에게 행해진 일에서 사용자와 함께 행해진 일로 바꾸는 단계다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;좋은 파괴적 변경 항목은 어떤 모습인가&lt;/h2&gt;
&lt;p&gt;좋은 항목은 첫 줄에서 영향을 받는 호출자를 이름으로 밝히고, 날짜를 명시하며, 수정 방법을 포함한다. 우리가 사용하는 형태로, 검증 강화 사례에 대한 예시는 다음과 같다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;도메인이 없는 이메일 주소는 2026년 11월 1일부터 거부됩니다.&lt;/strong&gt;
&lt;code&gt;POST /users&lt;/code&gt;와 &lt;code&gt;PATCH /users/:id&lt;/code&gt;는 현재 &lt;code&gt;alice@localhost&lt;/code&gt;와 같은 &lt;code&gt;email&lt;/code&gt; 값을 받아들이고 있습니다. 11월 1일부터 이들은 &lt;code&gt;400 invalid_email&lt;/code&gt;을 반환합니다. 내부 디렉터리로부터 사용자를 생성하는 모든 연동에 영향을 줍니다. 마이그레이션: 완전한 형식의 주소를 보내거나, 필드를 생략하고 나중에 설정하세요. 이미 도메인이 있는 주소를 사용 중이라면 변경할 필요가 없으며, 이는 올해 생성된 계정의 99.4%에 해당합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이런 공지가 어디에 있어야 하는지, 그리고 그 옆에 또 무엇이 있어야 하는지는
&lt;a href=&quot;https://changeloop.dev/blog/ko/api-changelog/&quot;&gt;API 체인지로그&lt;/a&gt;에서 다룬다.&lt;/p&gt;
&lt;p&gt;마지막 백분율은 장식이 아니다. 그것은 독자에게 걱정해야 할지 말지를 말해주며, 그것이 바로 독자가 그 항목을 열었을 때 갖고 있던 질문이다.&lt;/p&gt;
&lt;h2&gt;왜 그냥 피하지 않는가&lt;/h2&gt;
&lt;p&gt;대안이 더 나쁘기 때문이다. 아무것도 망가뜨리지 않는 API는 지금까지 저지른 모든 실수를 쌓아나간다. 잘못 붙인 필드 이름, 잘못된 기본값, 로컬 시간의 타임스탬프. 각각은 오후 한나절이면 이전할 수 있었을 호출자를 지키기 위해, 모든 새로운 호출자에게 영원히 부과되는 세금이다. 안정성에 대해 가장 좋은 평판을 가진 팀들은 좀처럼 무언가를 망가뜨리지 않으며, 그럴 때는 일정에 따라, 이전 경로와 함께, 대상에게 실제로 도달한 경고와 함께 그렇게 한다.&lt;/p&gt;
&lt;p&gt;그 경고의 메커니즘은 &lt;a href=&quot;https://changeloop.dev/blog/ko/api-deprecation/&quot;&gt;API를 비추천 처리하기&lt;/a&gt;라는 자매 글의 주제다. 그것을 알리는 항목은 &lt;a href=&quot;https://changeloop.dev/docs&quot;&gt;체인지로그 피드&lt;/a&gt;의 다른 어떤 항목과도 같은 방식으로 작성된다. 병합된 pull request로부터, 사람을 위해 보류되고, 그 후 영향을 받는 호출자들이 이미 읽고 있는 곳에 발행된다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;파괴적 변경과 비파괴적 변경의 차이는 무엇인가?&lt;/strong&gt;
파괴적 변경은 올바른 호출자가 계속 작동하기 위해 코드, 설정, 또는 데이터를 바꾸게 만든다. 비파괴적 변경은 기존의 모든 호출을 같은 의미로 계속 작동하게 둔다. 그래서 추가는 보통 안전하고, 제거, 이름 변경, 강화된 규칙은 보통 그렇지 않다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;필수 필드를 추가하는 것도 해당하는가?&lt;/strong&gt;
그렇다. 기존의 모든 호출이 그것을 생략하고 있으므로, 기존의 모든 호출이 이제 실패한다. 합리적인 기본값과 함께 선택적으로 추가하거나, 엔드포인트에 버전을 붙여라.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;버그 수정도 해당할 수 있는가?&lt;/strong&gt;
그럴 수 있다. 호출자가 버그가 있는 동작에 의존하고 있었다면, 그것을 고치는 것은 문서가 무엇이라고 말했든 그들을 망가뜨린다. 관찰 가능한 출력을 바꾸는 모든 수정은, 아무도 그것에 의존하지 않았다는 것을 보여줄 수 없는 한 파괴적으로 취급하라.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;시맨틱 버저닝이 웹 API에도 적용되는가?&lt;/strong&gt;
그 규칙은 적용된다. 파괴적 변경은 새 메이저 버전을 받고 예전 것은 정해진 기간 동안 계속 작동한다. 그 번호는 흔히 패키지 버전이 아니라 URL이나 날짜 헤더에 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;얼마나 미리 알려야 충분한가?&lt;/strong&gt;
호출자가 그 공지를 발견하고 작업을 처리할 수 있을 만큼. 90일이 공개 API에 대한 흔한 최소치이며, 원격으로 업데이트할 수 없는 채로 최종 사용자에게 출시되는 코드에서 쓰이는 것이라면 더 길어야 한다.&lt;/p&gt;
</content:encoded></item><item><title>체인지로그 쪽에서 고객 피드백 루프를 닫는 방법</title><link>https://changeloop.dev/blog/ko/customer-feedback-loop/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/customer-feedback-loop/</guid><description>피드백 루프는 요청한 사람에게 출시되었다고 알릴 때 닫힌다. 네 단계의 루프가 어디서 끊어지는지, 왜 체인지로그가 그것을 닫기에 알맞은지 설명한다.</description><pubDate>Sat, 29 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;고객 피드백 루프는 피드백을 준 사람이 그것이 어떻게 되었는지 통보받았을 때 닫힌다. 접수되었을 때도 아니고, 우선순위가 매겨졌을 때도 아니며, 심지어 출시되었을 때도 아니다. 통보받았을 때다. 대부분의 팀은 처음 세 단계는 잘 해내지만 마지막 단계는 전혀 하지 않으며, 그러고 나서 왜 피드백을 보내던 사람들이 더 이상 보내지 않는지 궁금해한다.&lt;/p&gt;
&lt;p&gt;이 글은 그 마지막 단계에 관한 것이며, 하나의 구체적인 주장에 관한 것이다. 체인지로그는 루프를 닫기에 알맞은 자리다. 그것이 루프를 닫을 수 있는 순간에 이미 존재하고 있는 유일한 산출물이기 때문이다.&lt;/p&gt;
&lt;h2&gt;고객 피드백 루프란 무엇인가&lt;/h2&gt;
&lt;p&gt;고객 피드백 루프는 사용자가 여러분에게 무언가를 말하는 것에서, 그 사용자가 여러분이 그것에 대해 무엇을 했는지 알게 되기까지의 경로다. 여기에는 네 단계가 있다. 피드백을 수집하고, 그것으로 무엇을 할지 결정하고, 결과를 출시하고, 요청한 사람에게 알리는 것. 네 번째 단계가 일어나기 전까지 루프는 열려 있다. 피드백을 수집하고 수정 사항을 출시하지만 아무에게도 알리지 않는 팀은 루프가 아니라 받은편지함을 갖고 있는 것이다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;단계&lt;/th&gt;
&lt;th&gt;무슨 일이 일어나는가&lt;/th&gt;
&lt;th&gt;보통 어디서 끊어지는가&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;수집&lt;/td&gt;
&lt;td&gt;피드백이 도착한다: 위젯, 지원팀, 영업팀, 인터뷰&lt;/td&gt;
&lt;td&gt;없음. 모든 팀이 이것은 한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;결정&lt;/td&gt;
&lt;td&gt;트리아지되고, 중복과 합쳐지고, 수락 또는 거절된다&lt;/td&gt;
&lt;td&gt;거절은 결코 전달되지 않는다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;출시&lt;/td&gt;
&lt;td&gt;누군가 그것을 만들고 공개된다&lt;/td&gt;
&lt;td&gt;병합 시점에 요청으로의 링크가 사라진다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;통보&lt;/td&gt;
&lt;td&gt;요청자가 그것이 출시되었음을 알게 된다&lt;/td&gt;
&lt;td&gt;생략되거나, 목소리 큰 요청자에게만 이루어진다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;이 글이 다루는 것은 네 번째 행이다. 그것이 끊어지는 이유는 문화적인 것이 아니라 구조적인 것이다. 기능이 출시될 무렵이면, 그것을 유발한 요청은 출시된 것과는 다른 시스템 안에 있으며, 그 둘을 연결하는 것을 자기 일로 삼는 사람은 아무도 없다. 루프는 더 앞에서, 요청을 애초에 어떻게 받느냐에서 시작되며, 문구와 타이밍은 &lt;a href=&quot;https://changeloop.dev/blog/ko/how-to-ask-for-customer-feedback/&quot;&gt;고객 피드백을 요청하는 방법&lt;/a&gt;에서 다룬다.&lt;/p&gt;
&lt;h2&gt;왜 피드백 루프는 열린 채로 남는가&lt;/h2&gt;
&lt;p&gt;피드백 루프가 열린 채로 남는 이유는 요청과 출시된 변경이 서로 다른 곳에 살고 있고, 그 둘 사이의 링크가 만들어진다면 손으로 만들어지기 때문이다. 요청은 피드백 도구, 지원팀 받은편지함, 혹은 스프레드시트 안에 있다. 변경은 pull request 안에 있다. 발표는 체인지로그나 이메일 안에 있다. 세 개의 시스템, 세 명의 소유자, 그리고 세 번째에서 첫 번째로 돌아가는 링크는 누군가 몇 달 후에 누가 요청했는지 기억해내는 것으로 만들어진다.&lt;/p&gt;
&lt;p&gt;두 번째 이유가 있다. 통보 단계는 보통 지원 업무(&amp;quot;그 사람에게 답하기&amp;quot;)가 아니라 마케팅 업무(&amp;quot;기능을 발표하기&amp;quot;)로 여겨진다. 발표는 모두에게 가고 특정한 누구에게도 닿지 않는다. 3월에 그 기능을 요청한 사람이 6월의 발표를 읽는다면, 그것을 답장이 아니라 뉴스로서 읽는다. 루프는 그 메시지가 본인에게 향해 있을 때만 닫힌다.&lt;/p&gt;
&lt;h2&gt;왜 체인지로그 쪽에서 루프를 닫는가&lt;/h2&gt;
&lt;p&gt;체인지로그 항목이야말로 정확히 알맞은 순간에 존재하고, 정확히 알맞은 말을 담고 있으며, 정확히 알맞은 사람에 의해 쓰이는 유일한 산출물이기 때문이다. 그것은 변경이 공개되었을 때 존재하며 그 이전에는 존재하지 않는다. 그것은 무엇이 바뀌었는지를 독자의 언어로 말하며, 그것이 바로 요청자가 필요로 하는 메시지다. 그리고 그것은 방금 그 pull request를 읽은 사람에 의해 쓰인다. 그것이 원래 요청으로의 링크가 여전히 보이는 유일한 순간이다.&lt;/p&gt;
&lt;p&gt;대안들과 비교해보자. 피드백 도구 쪽에서 루프를 닫으려면, 그 기능이 언제 출시되었는지를 피드백 도구가 알아야 하며, 이는 누군가 상태를 손으로 업데이트해야 한다는 뜻이다. pull request 쪽에서 닫으려면, 변경이 아직 공개되지 않은 병합 시점에 고객에게 알리게 되며, 배포가 지연되면 타임스탬프가 찍힌 깨진 약속이 된다. 마케팅 발표 쪽에서 닫으려면 발표가 나올 때까지 기다려야 하는데, 출시된 변경 대부분은 발표를 받지 못한다.&lt;/p&gt;
&lt;p&gt;체인지로그는 그 중간에 있다. 병합 이후, 릴리스의 순간에, 문구는 이미 완성된 채로.&lt;/p&gt;
&lt;h2&gt;루프는 단계별로 어떻게 닫히는가&lt;/h2&gt;
&lt;p&gt;이것은 우리가 운영하는 메커니즘이다. 여기서는 제품 투어가 아니라 사양으로 서술된다. 모든 단계는 손으로도, 다른 도구로도 할 수 있기 때문이며, 중요한 것은 순서다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;피드백은 그것을 고칠 저장소의 issue가 된다.&lt;/strong&gt; 위젯 제출은 라벨이 붙은 GitHub issue로 접수된다(&lt;code&gt;feature-request&lt;/code&gt; 또는 &lt;code&gt;bug&lt;/code&gt;, 우선순위, 그리고 &lt;code&gt;from-widget&lt;/code&gt;). 제출자의 이메일 주소는 issue 본문에 넣지 않는다. issue는 코드 바로 옆에 존재하므로, 세 번째 단계가 그것을 찾을 수 있다. 손으로 접수한 issue, 예를 들어 &lt;a href=&quot;https://changeloop.dev/blog/ko/feature-request-template/&quot;&gt;기능 요망 템플릿&lt;/a&gt;으로 만든 issue는 이 경로 밖에 있다. 다섯 번째 단계는 거기에 코멘트를 달지 않으므로, 그 루프는 직접 닫아라.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;수정 사항이 그 issue를 참조한다.&lt;/strong&gt; pull request는 &lt;code&gt;Fixes #142&lt;/code&gt;라고 적는다. GitHub 자체의 클로즈 키워드다. 새로 배울 것이 없고, 개발자가 이미 쓰고 있는 것과 같은 문장이다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;체인지로그 항목은 병합된 pull request로부터 초안이 작성되며 링크를 운반한다.&lt;/strong&gt; 병합 시점에 초안이 생성되고, &lt;code&gt;#142&lt;/code&gt;가 PR 본문에서 읽혀 초안에 붙는다. 링크는 아직 저렴할 때, 기계에 의해, 이미 그곳에 있는 데이터로부터 만들어진다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;사람이 그 항목을 검토한다.&lt;/strong&gt; 문구, 대상 독자, 애초에 발행해야 하는지. 폐기된 초안은 아무것도 닫지 않으며, 그것은 옳다. 우연히 issue를 참조했던 내부 리팩터링은 뉴스가 아니기 때문이다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;승인되면 요청자에게 알린다.&lt;/strong&gt; 피드백으로 만들어진 issue에 코멘트가 게시된다. &amp;quot;Shipped —&amp;quot;에 이어 항목의 제목과 발행된 항목으로의 링크가 붙는다. 그리고 위젯은 제출자에게 같은 출시된 항목을 보여준다. 한 번만, 결코 두 번은 아니며, 사람이 그 항목을 발행한 후에만. 같은 항목은 요청하지 않았던 모든 사람에게 &lt;a href=&quot;https://changeloop.dev/docs&quot;&gt;피드와 위젯&lt;/a&gt;을 통해 전달된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;5단계의 순서가 이 설계의 전부다. 병합 시점에 요청자에게 알리는 것이 더 이르고 쉬웠겠지만, 그것은 배포가 지연되는 빈도만큼이나 자주 틀린 것이 되었을 것이다. 피처 플래그는 이 순서마저 깨뜨리는데, 승인과 게시가 기능이 요청자의 계정에는 여전히 보이지 않는 동안 일어날 수 있기 때문이다. &lt;a href=&quot;https://changeloop.dev/blog/ko/feature-flags-feature-requests/&quot;&gt;피처 플래그와 기능 요청&lt;/a&gt;은 플래그가 개입할 때 이 단계가 필요로 하는 추가 확인을 다룬다.&lt;/p&gt;
&lt;h2&gt;고객에게 닫힌 루프는 어떻게 보이는가&lt;/h2&gt;
&lt;p&gt;그것은 답장처럼 보인다. 고객은 위젯을 통해 요청을 보냈다. 그러던 어느 날 위젯이 그것을 출시됨으로 보여주고, 자신의 언어로 그것을 설명하는 항목으로의 링크가 함께 온다. GitHub에서는 issue에도 같은 소식이 코멘트로 달린다. 그들은 뉴스레터를 구독하지도, 로드맵을 확인하지도, 체인지로그를 검색하지도 않았다. 통보받은 것이다.&lt;/p&gt;
&lt;p&gt;바로 그 경험이 두 번째 피드백을 일으킨다. 사람들은 답해주는 제품에 피드백을 보낸다. &lt;a href=&quot;https://changeloop.dev/changelog-examples&quot;&gt;체인지로그 예시&lt;/a&gt; 페이지에는 사용자들이 눈에 띄게 계속 요청을 보내오는 팀들의 항목이 담겨 있으며, 공통점은 도구가 아니다. 항목이 답장처럼 읽힌다는 것이다.&lt;/p&gt;
&lt;h2&gt;피드백 루프는 어떻게 측정하는가&lt;/h2&gt;
&lt;p&gt;출시된 변경 중 적어도 한 명의 요청자에게 알린 비율과, 출시부터 통보까지의 시간을 측정하라. 두 개의 숫자이며, 링크가 존재하면 둘 다 쉽고, 존재하지 않으면 둘 다 불가능하다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;클로즈율&lt;/strong&gt;: 이번 달에 발행된 체인지로그 항목 중 적어도 하나의 요청에 링크된 것이 몇 개이고, 그중 요청자에게 통보한 것이 몇 개인가. 두 번째 숫자가 첫 번째보다 훨씬 낮다면 통보가 실패하고 있는 것이고, 첫 번째가 낮다면 요청이 pull request에서 참조되고 있지 않은 것이며, 그 해법은 PR 템플릿에 한 문장을 추가하는 것이다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;출시-통보 시간&lt;/strong&gt;: 항목이 공개된 시점부터 요청자가 통보받는 시점까지의 시간. 위의 메커니즘이 있으면 몇 초다. 손으로 하면 대개 몇 주, 또는 영원히 오지 않으며, 그 &amp;quot;영원히&amp;quot;가 중요한 숫자다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;수집된 피드백의 양으로 루프를 측정하지 마라. 수집은 쉬운 단계이며, 그것을 측정하는 팀은 그것을 최적화하게 되고, 그것은 더 많은 열린 루프를 만들어낸다.&lt;/p&gt;
&lt;h2&gt;로드맵은 어디에 들어맞는가&lt;/h2&gt;
&lt;p&gt;공개 로드맵은 루프를 일찍 닫는 방법이다. 요청자에게 그들의 요청이 출시되기 전에 이미 들려졌다고 말해준다. 유용하지만, 마지막 단계를 대신하지는 못한다. &amp;quot;계획됨&amp;quot;은 미래에 대한 약속이고, &amp;quot;출시됨&amp;quot;은 현재에 대한 사실이다. 같은 issue들로부터, 열마다 라벨 하나로 &lt;a href=&quot;https://changeloop.dev/blog/ko/public-roadmap/&quot;&gt;공개 로드맵&lt;/a&gt;을 운영하라. 그러면 같은 요청이 어디에도 다시 입력되지 않고 계획됨에서 출시됨으로 이동한다. 출시됨으로의 이동은 라벨 변경(&lt;code&gt;roadmap:shipped&lt;/code&gt;)이며, 항목이 승인될 때 그것을 대신 해주는 것은 없으므로 같은 검토에서 처리하라.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;고객 피드백 루프의 네 단계는 무엇인가?&lt;/strong&gt;
수집, 결정, 출시, 통보다. 네 번째 단계가 일어나기 전까지 루프는 열려 있다. 많은 프레임워크가 중간에 분석과 우선순위 지정 단계를 추가하지만, 그것들은 &amp;quot;결정&amp;quot;의 세분화일 뿐이며 그중 무엇도 아무것도 닫지 않는다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;요청을 거절할 때도 고객에게 알려야 하는가?&lt;/strong&gt;
그래야 하며, 그것은 루프에서 가장 소홀히 되는 메시지다. &amp;quot;이것은 하지 않겠습니다, 그리고 이유는 이렇습니다&amp;quot;라는 명확한 말은 기다림을 끝낸다. 침묵은 루프를 영원히 열어두고 고객이 계속 확인하게 만든다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;루프를 닫는 것과 기능을 발표하는 것은 어떻게 다른가?&lt;/strong&gt;
발표는 모두에게 간다. 루프를 닫는 것은 요청했던 사람들에게, 그들이 요청했던 경로로 답하는 것이다. 둘 다 하라. 그것들은 서로 다른 독자를 위한 서로 다른 메시지다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;요청자가 GitHub을 쓰지 않는다면 어떻게 하는가?&lt;/strong&gt;
대부분은 쓰지 않으며, 그래도 괜찮다. 위젯은 그들이 보낸 것의 상태를 출시된 항목과 그 링크까지 포함해 계속 보여주므로, 그들은 글을 남긴 페이지 외에는 아무것도 필요 없다. issue의 코멘트는 저장소를 볼 수 있는 사람들을 위한 것이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;이 루프는 GitHub 대신 GitLab이나 Bitbucket에서도 작동하는가?&lt;/strong&gt;
위젯과 체인지로그는 작동하지만, 다섯 번째 단계의 자동 코멘트는 아직 작동하지 않는다. GitLab이나 Bitbucket을 쓰는 팀도 모든 제출을 그대로 받고, 그것을 issue로 등록하고, 위젯에 요청자의 상태를 계속 보여줄 수 있다. 다만 그 루프를 issue 자체에 다시 닫아 거는 것은 해당 연동이 생기기 전까지는 손으로 해야 하는 단계다.&lt;/p&gt;
</content:encoded></item><item><title>체인지로그 항목이 되는 기능 요망 템플릿</title><link>https://changeloop.dev/blog/ko/feature-request-template/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/feature-request-template/</guid><description>기능 요청은 출시되는 순간 다시 찾을 수 있어야 쓸모가 있다. 요청을 올바른 곳으로 보내는 라벨과 나중에 체인지로그가 읽을 필드를 살펴본다.</description><pubDate>Sat, 29 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;기능 요망 템플릿은 네 가지 질문으로 이루어진 폼이다. 그 사람이 무엇을 하려고 하는지, 무엇이 그것을 막는지, 대신 무엇을 시도해봤는지, 그리고 완료되었을 때 어떻게 통보받고 싶은지. 보통 여기에 함께 등장하는 다른 모든 것, 즉 우선순위 선택지, 공수 추정, 비즈니스 가치 점수는 요청을 받는 팀을 위한 것이며, 그것을 보내는 사람이 잘못 채워 넣게 되는 부분이다.&lt;/p&gt;
&lt;p&gt;깔끔한 요청은 템플릿에 대한 잘못된 시험이다. 옳은 시험은 이렇다. 여섯 달 후, 그 기능이 출시되었을 때, 누군가 그 요청을 찾아내고, 이해하고, 그것을 쓴 사람에게 알릴 수 있는가? 대부분의 템플릿은 접수를 위해 설계되어 있다. 이것은 루프가 닫히는 그날을 위해 설계되어 있다.&lt;/p&gt;
&lt;h2&gt;기능 요망 템플릿에는 무엇을 포함해야 하는가&lt;/h2&gt;
&lt;p&gt;목표, 장애물, 우회 방법, 그리고 요청자로 돌아가는 길을 포함해야 한다. 그 순서로 네 개의 필드가 있으며, 각각이 팀이 나중에 물을 질문에 답한다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;필드&lt;/th&gt;
&lt;th&gt;나중에 답하는 질문&lt;/th&gt;
&lt;th&gt;폼에 있는 이유&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;무엇을 하려고 하십니까?&lt;/td&gt;
&lt;td&gt;우리가 만든 기능이 그들이 필요로 했던 것인가?&lt;/td&gt;
&lt;td&gt;목표는 어떤 구체적인 제안보다도 오래 살아남는다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;오늘 무엇이 그것을 막고 있습니까?&lt;/td&gt;
&lt;td&gt;&amp;quot;완료&amp;quot;란 어떤 모습인가?&lt;/td&gt;
&lt;td&gt;수정 방법을 규정하지 않고 간극만을 이름으로 밝힌다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;대신 무엇을 하고 계십니까?&lt;/td&gt;
&lt;td&gt;이것이 실제로 얼마나 긴급한가?&lt;/td&gt;
&lt;td&gt;고통스러운 우회 방법은 우선순위 선택지보다 강한 신호다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;어떻게 알려드리면 될까요?&lt;/td&gt;
&lt;td&gt;&amp;quot;출시됨&amp;quot; 메시지는 누구에게 가는가?&lt;/td&gt;
&lt;td&gt;대부분의 템플릿이 빠뜨리는 필드다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;의도적으로 빠져 있는 것: 필수 필드로서의 제안된 해결책(코멘트로는 환영하지만 틀에는 넣지 않는다), 우선순위 선택지(모든 제출자가 높음을 고른다), 그리고 공수나 가치에 대한 어떤 추정치도(그것은 트리아지 이후 팀의 몫이다). 해결책을 묻는 템플릿은 버튼에 대한 요청을 얻고, 목표를 묻는 템플릿은 결과에 대한 요청을 얻으며, 결과야말로 체인지로그 항목이 쓰이는 대상이다.&lt;/p&gt;
&lt;h2&gt;템플릿&lt;/h2&gt;
&lt;p&gt;이것은 우리가 사용하는 GitHub issue 템플릿을 폼으로 나타낸 것이다. &lt;code&gt;.github/ISSUE_TEMPLATE/feature_request.yml&lt;/code&gt;에 붙여넣으면 New Issue 페이지에서 구조화된 폼으로 렌더링된다. 이를 통해 접수된 요청은 피드백 위젯으로 접수된 것과 같은 필드를 가진 issue로 착지하며, 이는 바로 다음 절에서 중요해진다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;name: Feature request
description: What you are trying to do, and what stops you.
labels: [&amp;quot;feature-request&amp;quot;]
body:
  - type: textarea
    id: goal
    attributes:
      label: What are you trying to do?
      description: &amp;gt;-
        The outcome, not the button. &amp;quot;Export a month of invoices as one
        PDF&amp;quot; beats &amp;quot;add a PDF export&amp;quot;.
    validations:
      required: true
  - type: textarea
    id: blocker
    attributes:
      label: What stops you today?
      description: &amp;gt;-
        Where the product runs out. An error, a missing option, a limit.
    validations:
      required: true
  - type: textarea
    id: workaround
    attributes:
      label: What do you do instead?
      description: &amp;gt;-
        The spreadsheet, the script, the manual step. &amp;quot;Nothing, I gave
        up&amp;quot; is a valid answer.
  - type: input
    id: contact
    attributes:
      label: How should we tell you when it ships?
      description: &amp;gt;-
        An email address, or leave blank to be notified only on this
        issue.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;두 가지 세부 사항이 일을 해낸다. &lt;code&gt;labels: [&amp;quot;feature-request&amp;quot;]&lt;/code&gt;는 누군가 트리아지할 때까지 기다리는 대신 생성 시점에 요청이 분류된다는 뜻이다. 그리고 마지막 필드가 존재하는 이유는 &amp;quot;알려드리겠습니다&amp;quot;가 약속이며, 약속에는 주소가 필요하기 때문이다.&lt;/p&gt;
&lt;h2&gt;기능 요망은 어떤 라벨을 가져야 하는가&lt;/h2&gt;
&lt;p&gt;기능 요망은 그것이 무엇인지에 대한 라벨 하나, 얼마나 긴급한지에 대한 라벨 하나, 그리고 어디서 왔는지에 대한 라벨 하나를 가져야 한다. 세 개의 라벨, 세 개의 축이며, 각각을 서로 다른 독자가 읽는다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;라벨&lt;/th&gt;
&lt;th&gt;값&lt;/th&gt;
&lt;th&gt;누가 읽는가&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;종류&lt;/td&gt;
&lt;td&gt;&lt;code&gt;feature-request&lt;/code&gt;, &lt;code&gt;bug&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;어느 큐에 들어갈지 결정하는 사람&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;우선순위&lt;/td&gt;
&lt;td&gt;&lt;code&gt;priority:low&lt;/code&gt;, &lt;code&gt;priority:medium&lt;/code&gt;, &lt;code&gt;priority:high&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;다음 사이클을 계획하는 사람&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;출처&lt;/td&gt;
&lt;td&gt;&lt;code&gt;from-widget&lt;/code&gt;, &lt;code&gt;from-form&lt;/code&gt;, &lt;code&gt;from-support&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;요청이 어디서 오는지 측정하는 사람&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;위젯은 제출물을 issue로 접수할 때 처음 두 축과 &lt;code&gt;from-widget&lt;/code&gt;을 적용한다. &lt;code&gt;from-form&lt;/code&gt;과 &lt;code&gt;from-support&lt;/code&gt;는 다른 경로로 들어오는 요청을 위한 제안이다. 위젯의 라벨은 종류(&lt;code&gt;bug&lt;/code&gt;인지 &lt;code&gt;feature-request&lt;/code&gt;인지는 메시지만으로 분류기가 판단한다), 우선순위(차분하고 구체적인 크래시 리포트는 높음, 이미 물었던 것의 중복은 낮음, 보안 문제를 조금이라도 암시하는 것은 문구와 무관하게 &lt;code&gt;bug&lt;/code&gt;이면서 높음), 그리고 &lt;code&gt;from-widget&lt;/code&gt;. 같은 세 개의 축은 위의 템플릿을 통해 손으로 도착하는 요청에도 똑같이 작동하며, 그것이 요점이다. 요청은 어디로 들어왔든 요청이라는 것.&lt;/p&gt;
&lt;p&gt;한 가지 관례가 더 있다. 위젯은 접수하기 전에 issue 본문에서 제출자의 이메일 주소를 제거한다. issue는 공개될 수도 있는 저장소 안에 있기 때문이다. 대신 제출 참조 번호로 대체한다. 그 주소는 issue에 들어가지 않으며, 제출자는 결과를 위젯 자체에서 확인한다. 여러분의 트래커가 팀 밖에서 보인다면 연락처 필드에도 똑같이 하라.&lt;/p&gt;
&lt;h2&gt;기능 요망은 어떻게 체인지로그 항목이 되는가&lt;/h2&gt;
&lt;p&gt;기능 요망이 체인지로그 항목이 되는 것은 pull request가 그 issue를 닫고, 그 pull request로부터 초안이 작성된 항목이 그곳으로 링크를 걸 때다. 그 메커니즘은 GitHub 자체의 클로즈 키워드다. 설명에 &lt;code&gt;Fixes #142&lt;/code&gt;라고 적힌 PR은 병합 시점에 issue 142를 닫는다. 여러분의 체인지로그 항목이 병합된 pull request로부터 초안이 작성된다면, 그 초안은 issue 번호를 함께 운반할 수 있고, 항목은 누가 요청했는지 알게 된다.&lt;/p&gt;
&lt;p&gt;그것이 템플릿이 해결책이 아니라 목표를 묻는 이유다. 항목이 쓰일 때, 목표는 작성자가 필요로 하는 문장이 된다. &amp;quot;이제 청구서를 한 달치씩 모아 하나의 PDF로 내보낼 수 있습니다&amp;quot;는 체인지로그 항목이다. &amp;quot;PDF 내보내기 추가&amp;quot;는 커밋 메시지다. pull request로부터 초안을 작성하는 &lt;a href=&quot;https://changeloop.dev/changelog-tools&quot;&gt;체인지로그 도구&lt;/a&gt;는 수집과 링크를 처리할 수 있지만, 문구에는 여전히 사람이 필요하며, 그 사람에게는 목표가 필요하다.&lt;/p&gt;
&lt;h2&gt;출시되었을 때 무슨 일이 일어나는가&lt;/h2&gt;
&lt;p&gt;요청자는 항목으로의 링크와 함께 통보받는다. 우리의 방식에서 그것은 위젯을 통해 들어온 요청에 대해 자동으로 이루어진다. 사람이 그 항목을 승인한 후 issue에 게시되는 &amp;quot;Shipped — &amp;lt;항목 제목&amp;gt;&amp;quot;이라는 코멘트이며, 발행된 항목으로의 링크가 함께 오고, 동시에 위젯은 제출자에게 같은 항목을 보여준다. 이 템플릿으로 손으로 접수한 issue에는 자동 코멘트가 달리지 않으니, 같은 규칙에 따라 그 루프를 직접 닫아라. 코멘트는 병합 시점이 아니라 승인 시점에 의도적으로 게시된다. 무언가가 아직 공개되지 않았는데 공개되었다고 말하는 코멘트는 타임스탬프가 찍힌 깨진 약속이기 때문이다. 각 요청은 많아야 한 번 통보받는다. 같은 항목을 두 번 승인해도 두 번째 코멘트는 생기지 않는다.&lt;/p&gt;
&lt;p&gt;이것을 손으로 한다면, 규칙은 같다. pull request 시점에 루프를 닫지 마라. 발행된 항목에서 닫고, 한 번만 닫아라. &lt;a href=&quot;https://changeloop.dev/docs&quot;&gt;피드와 위젯&lt;/a&gt;은 요청하지 않았던 사람들, 즉 대부분의 사람들에게 같은 항목을 전달한다. 코멘트는 요청했던 그 사람을 위한 것이다.&lt;/p&gt;
&lt;h2&gt;왜 대부분의 기능 요망 템플릿은 실패하는가&lt;/h2&gt;
&lt;p&gt;그것들은 트리아지를 쉽게 만들도록 설계되어 있고 실제로 성공하지만, 요청자에게 중요한 유일한 순간을 희생시킨다. 열두 개의 필드를 가진 템플릿은 요청 수가 줄어들고, 그것이 얻는 요청은 열두 개의 필드를 채울 인내심을 가진 사람들로부터 온다. 이는 그 기능을 필요로 하는 사람들과 같은 집단이 아니다. 네 개의 필드를 가지고, 그중 하나가 &amp;quot;어떻게 연락드리면 될까요&amp;quot;인 템플릿은 더 많은 요청을 얻으며 그 모두에 응답할 수 있다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;기능 요망 템플릿은 우선순위를 물어야 하는가?&lt;/strong&gt;
아니다. 대신 우회 방법을 물어라. &amp;quot;매주 금요일마다 스프레드시트로 내보내서 다시 입력하고 있습니다&amp;quot;는 제출자가 높음으로 설정한 드롭다운보다 우선순위에 대해 더 많은 것을 말해준다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;요청자는 해결책을 제안해야 하는가?&lt;/strong&gt;
자유 텍스트 안에서는 그럴 수 있다. 그것을 틀로 만들지는 마라. 해결책으로 쓰인 요청은 서로 합치기가 더 어렵고, 그것에 대해 체인지로그 항목을 쓰기도 더 어렵다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;기능 요망은 공개 로드맵에 나타나야 하는가?&lt;/strong&gt;
계획된 후에는 그렇다. 같은 issue에 붙은 라벨이 그것을 계획됨 열에 넣고, 요청자는 그것이 움직이는 것을 지켜볼 수 있다. &lt;a href=&quot;https://changeloop.dev/blog/ko/public-roadmap/&quot;&gt;공개 로드맵&lt;/a&gt; 글이 그 메커니즘이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;중복은 어떻게 처리하는가?&lt;/strong&gt;
새 요청을 기존 issue에 링크하고 낮은 우선순위 라벨을 붙여라. 닫지는 마라. 각각의 중복은 그것이 출시될 때 알려야 할 또 한 명이다. Changeloop의 자동 코멘트로는 pull request가 그 사람의 issue도 지정해야만(&lt;code&gt;Fixes #142, fixes #187&lt;/code&gt;) 그 사람에게 알림이 간다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;템플릿은 어디에 있어야 하는가?&lt;/strong&gt;
pull request를 받게 될 저장소 안이다. 그래야 클로즈 키워드가 작동한다. 별도의 트래커에 있는 요청은 병합 시점에 손으로 링크해야 하며, 그 단계가 바로 생략되기 쉬운 단계다.&lt;/p&gt;
</content:encoded></item><item><title>issue 트래커로 만드는 세 개의 열로 이루어진 공개 로드맵</title><link>https://changeloop.dev/blog/ko/public-roadmap/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/public-roadmap/</guid><description>공개 로드맵은 미래에 대한 약속이므로 작게 유지하고, 이미 추적하는 issue로 만들며, 항목은 issue에 붙인 라벨 하나로 열 사이를 옮기는 편이 좋다.</description><pubDate>Sat, 29 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;공개 로드맵은 여러분이 만들고자 하는 것의 목록이며, 고객이 볼 수 있는 곳에 발행된다. 일을 하고 있는 단어는 &lt;em&gt;의도&lt;/em&gt;다. 로드맵은 미래에 대한 일련의 약속이며, 그 위의 모든 항목은 여러분이 지키거나, 아니면 지키지 않은 것으로 보이게 될 것들이다. 그것이 로드맵을 발행하는 이유이며, 동시에 대부분의 공개 로드맵이 한 분기 안에 낡아버리는 이유이기도 하다. 살아남는 버전은 작고, 이미 유지하고 있는 데이터로부터 도출되며, 저 끝에서 체인지로그와 연결되어 있어서, 아무도 다시 입력하지 않아도 약속이 사실이 된다.&lt;/p&gt;
&lt;h2&gt;공개 로드맵은 무엇을 위한 것인가&lt;/h2&gt;
&lt;p&gt;공개 로드맵은 요청을 가진 고객에게, 그것이 출시되기 전에 그 요청이 들려졌다는 것을 알려준다. 그것은 루프를 닫는 것의 이른 절반이다. &amp;quot;계획됨&amp;quot;은 &amp;quot;누군가 이것을 읽었는가&amp;quot;라는 질문에 답하고, &amp;quot;구축 중&amp;quot;은 &amp;quot;실제로 일어나고 있는가&amp;quot;에 답한다. 둘 다 마지막 단계, 즉 출시되었을 때 요청자에게 알리는 것을 대신하지는 못하지만, 둘 다 그 사이에 물어보는 사람의 수를 줄여준다.&lt;/p&gt;
&lt;p&gt;그것은 팀을 위해서도 한 가지 역할을 한다. 공개적인 약속을 강제하는 것이며, 이는 아무도 만들지 않을 사백 개의 항목을 조용히 품고 있는 백로그에 대해 알려진 가장 저렴한 치료법이다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;열&lt;/th&gt;
&lt;th&gt;그것이 하는 약속&lt;/th&gt;
&lt;th&gt;무엇이 항목을 그 안으로 옮기는가&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;계획됨&lt;/td&gt;
&lt;td&gt;우리는 이것을 만들 의도가 있다&lt;/td&gt;
&lt;td&gt;결정, issue에 라벨로 기록됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;구축 중&lt;/td&gt;
&lt;td&gt;지금 누군가 그것을 작업하고 있다&lt;/td&gt;
&lt;td&gt;issue의 &lt;code&gt;roadmap:building&lt;/code&gt; 라벨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;출시됨&lt;/td&gt;
&lt;td&gt;공개되어 있다&lt;/td&gt;
&lt;td&gt;&lt;code&gt;roadmap:shipped&lt;/code&gt; 라벨, 또는 그 라벨이 붙은 채로 issue를 닫는 것&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;고정된 순서의 세 개 열이면 충분하다. 네 번째 열(&amp;quot;검토 중&amp;quot;, &amp;quot;리뷰 중&amp;quot;, &amp;quot;백로그&amp;quot;)은 좋은 의도가 박물관이 되어가는 곳이며, 고객이 가장 먼저 무시하는 법을 배우는 열이기도 하다.&lt;/p&gt;
&lt;h2&gt;로드맵을 공개해야 하는가&lt;/h2&gt;
&lt;p&gt;작고 정직하게 유지할 수 있다면 공개하라. 대안이 &amp;quot;할 수도 있음&amp;quot;이 잔뜩 나열된 긴 목록이라면 비공개로 유지하라. 공개 로드맵의 대가는 그것을 발행하는 것 자체와는 무관하다. 그 위의 모든 항목은 이제 누군가 지원팀에서, 영업 전화에서, 갱신 대화에서 물어볼 질문이 된다. 여러분이 만들 열 개의 항목은 자산이다. 만들지도 모를 예순 개의 항목은 왜 안 만들었는지에 대한 예순 번의 미래 대화다.&lt;/p&gt;
&lt;p&gt;발행하지 않을 정직한 이유가 두 가지 있다. 여러분의 계획이 한 분기보다 빨리 바뀌거나, 경쟁사가 고객보다 여러분의 로드맵을 더 꼼꼼히 읽는 경우다. 둘 다 실재하며, 둘 다 아무것도 발행하지 않는 것이 아니라 더 적게 발행하는 것으로 답할 수 있다. &amp;quot;구축 중&amp;quot;만 공개하고 &amp;quot;계획됨&amp;quot;은 내부에 두어도, 요청자에게 자신의 issue가 움직이고 있다는 것은 여전히 전달된다.&lt;/p&gt;
&lt;h2&gt;GitHub issue로부터 공개 로드맵을 어떻게 만드는가&lt;/h2&gt;
&lt;p&gt;이미 추적하고 있는 issue에 열마다 라벨을 붙이고, 라벨이 붙은 issue를 로드맵으로 렌더링하라. 아무것도 다시 입력되지 않고, 로드맵은 실제 작업으로부터 어긋날 수 없으며, 고객의 요청으로 시작된 바로 그 issue가 정체성을 바꾸지 않은 채 열들을 통과해 나간다.&lt;/p&gt;
&lt;p&gt;우리가 운영하는 메커니즘은 이렇다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;열마다 하나의 라벨, 고정된 접두사와 함께&lt;/strong&gt;: &lt;code&gt;roadmap:planned&lt;/code&gt;, &lt;code&gt;roadmap:building&lt;/code&gt;, &lt;code&gt;roadmap:shipped&lt;/code&gt;. 연결된 저장소 안에서 이 중 하나를 가진 모든 issue는 그 열에 나타난다. 셋 중 아무것도 없는 issue는 로드맵에 없으며, 그것이 대부분의 issue이고, 그것이 옳다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;열은 항상 같은 순서로 나열된 배열이다.&lt;/strong&gt; 계획됨, 구축 중, 출시됨. 이름을 키로 하는 맵이 아니므로, 독자(혹은 위젯)는 절대 순서를 추측할 필요가 없다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;issue가 두 개의 라벨을 가지면, 가장 진행된 쪽이 이긴다.&lt;/strong&gt; 누군가 &lt;code&gt;roadmap:planned&lt;/code&gt;를 제거하기 전에 &lt;code&gt;roadmap:shipped&lt;/code&gt;를 먼저 추가할 것이다. &amp;quot;가장 마지막에 도착한 웹훅&amp;quot;으로 움직이는 상태 기계는 전달 순서에 따라 항목을 서로 다른 열에 놓게 될 것이다. 라벨 집합만으로 판단하면, 이벤트가 어떤 순서로 도착하든 답은 같아진다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;출시됨은 다른 것들과 마찬가지로 라벨 상태다.&lt;/strong&gt; issue에 &lt;code&gt;roadmap:shipped&lt;/code&gt;가 붙거나, 그 라벨을 단 채로 닫히면 카드가 옮겨진다. 카드 자체는 체인지로그 항목으로 링크되지 않는다. 세부 내용은 그 issue를 닫은 pull request로부터 초안이 작성된 항목에 있다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;데이터로 제공하라.&lt;/strong&gt; 로드맵은 그 세 개의 열을 가진 JSON 문서이며, 체인지로그 피드와 같은 캐시 헤더로 나란히 발행되어서, 문서 사이트, 위젯, 상태 페이지가 두 번째 통합 없이 그것을 렌더링할 수 있다. &lt;a href=&quot;https://changeloop.dev/docs&quot;&gt;피드 문서&lt;/a&gt;에 정확한 형태가 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;라벨 하나는 관리자에게 요구하기에 작은 것이며, 그것이 통합의 전부다. 동기화를 유지해야 할 보드도 없고, 로그인해야 할 별도의 도구도 없으며, 고객이 접수한 요청이 곧 로드맵 위의 항목이다. 출시되어도 그것은 같은 항목이다.&lt;/p&gt;
&lt;h2&gt;공개 로드맵에는 무엇을 담지 말아야 하는가&lt;/h2&gt;
&lt;p&gt;날짜, 추정치, 그리고 아홉 달 후에 질문받으면 곤란해질 만한 것은 담지 말아야 한다. 날짜는 전형적인 실수다. 로드맵 위의 한 분기는 영업 자료 속의 확약이 되고, 그것은 &amp;quot;당신은 Q3라고 했잖아요&amp;quot;라는 제목의 티켓이 된다. 열만으로도 충분히 전달된다. &amp;quot;구축 중&amp;quot;은 이미 &amp;quot;누군가 그것에 매달릴 만큼 가까운 시일 안에&amp;quot;를 의미한다.&lt;/p&gt;
&lt;p&gt;내부 백로그도 담지 말아야 한다. 삼백 개의 항목을 가진 로드맵은 약속이 아니라 검색 문제이며, 자신의 요청을 212번째 자리에서 찾은 고객은 여러분이 말할 의도가 없었던 무언가를 알게 된 것이다.&lt;/p&gt;
&lt;h2&gt;로드맵은 체인지로그와 어떻게 연결되는가&lt;/h2&gt;
&lt;p&gt;로드맵과 체인지로그는 같은 issue들을 두 쪽에서 서술하며, 하나는 미래를 위해, 하나는 과거를 위해 있다. 별도의 보드에서 카드를 옮기는 사람은 없다. 관리자는 이미 작업하고 있던 issue의 라벨을 바꾸고, 그 pull request로부터 항목의 초안이 작성되며, 사람이 그 항목을 승인하면 위젯 피드백이 그 issue가 된 요청자는 그 issue에서 통보받는다. 카드를 출시됨으로 옮기는 것은 여전히 별도의 단계, 즉 &lt;code&gt;roadmap:shipped&lt;/code&gt; 라벨이므로 같은 검토의 일부로 만들어라. 항목을 승인한다고 그것이 대신 이루어지지는 않는다.&lt;/p&gt;
&lt;p&gt;이것은 &lt;a href=&quot;https://changeloop.dev/blog/ko/customer-feedback-loop/&quot;&gt;피드백 루프 글&lt;/a&gt;이 체인지로그 쪽에서 서술하는 것과 같은 루프이며, 로드맵은 그 한가운데서 고객이 보는 것이다. &lt;a href=&quot;https://changeloop.dev/changelog-tools&quot;&gt;체인지로그 도구&lt;/a&gt; 정리는 어떤 제품이 로드맵 뷰를 제공하고 어떤 제품이 그것을 별도의 보드로 취급하는지를 다루며, 그것이 정확성을 유지하는지를 결정하는 차이다.&lt;/p&gt;
&lt;h2&gt;좋은 공개 로드맵은 어떤 모습인가&lt;/h2&gt;
&lt;p&gt;짧아 보이고, 그 위의 모든 항목이 누군가 열어볼 수 있는 issue다. 시험은 고객이 어떤 항목에서 그 뒤의 논의로, 그리고 출시된 항목에서 실제로 무엇이 바뀌었는지 설명하는 항목으로 갈 수 있는가다. 들어갈 방법이 없는 기능 이름들의 목록인 로드맵은 브로슈어일 뿐이다.&lt;/p&gt;
&lt;p&gt;위젯이 가져올 JSON으로서 작성된 구체적인 예시다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;columns&amp;quot;: [
    { &amp;quot;column&amp;quot;: &amp;quot;planned&amp;quot;, &amp;quot;hasMore&amp;quot;: false, &amp;quot;items&amp;quot;: [
      { &amp;quot;id&amp;quot;: &amp;quot;6b0c1f...&amp;quot;, &amp;quot;column&amp;quot;: &amp;quot;planned&amp;quot;,
        &amp;quot;publicTitle&amp;quot;: &amp;quot;Saved views on the inbox&amp;quot;,
        &amp;quot;publicDescription&amp;quot;: &amp;quot;Keep a filter you use often and come back to it.&amp;quot;,
        &amp;quot;publishedAt&amp;quot;: &amp;quot;2026-09-16T10:04:11.000Z&amp;quot; }
    ]},
    { &amp;quot;column&amp;quot;: &amp;quot;building&amp;quot;, &amp;quot;hasMore&amp;quot;: false, &amp;quot;items&amp;quot;: [
      { &amp;quot;id&amp;quot;: &amp;quot;71a4e2...&amp;quot;, &amp;quot;column&amp;quot;: &amp;quot;building&amp;quot;,
        &amp;quot;publicTitle&amp;quot;: &amp;quot;Roadmap column in the widget&amp;quot;,
        &amp;quot;publicDescription&amp;quot;: &amp;quot;See what is coming without leaving the page.&amp;quot;,
        &amp;quot;publishedAt&amp;quot;: &amp;quot;2026-09-12T08:20:02.000Z&amp;quot; }
    ]},
    { &amp;quot;column&amp;quot;: &amp;quot;shipped&amp;quot;, &amp;quot;hasMore&amp;quot;: false, &amp;quot;items&amp;quot;: [
      { &amp;quot;id&amp;quot;: &amp;quot;5c9d70...&amp;quot;, &amp;quot;column&amp;quot;: &amp;quot;shipped&amp;quot;,
        &amp;quot;publicTitle&amp;quot;: &amp;quot;Feedback filed as labelled issues&amp;quot;,
        &amp;quot;publicDescription&amp;quot;: &amp;quot;Widget submissions arrive as issues your triage already handles.&amp;quot;,
        &amp;quot;publishedAt&amp;quot;: &amp;quot;2026-09-02T15:41:37.000Z&amp;quot; }
    ]}
  ],
  &amp;quot;enabled&amp;quot;: true,
  &amp;quot;language&amp;quot;: &amp;quot;en&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;세 개의 열에 걸친 세 개의 항목만으로도 더없이 좋은 공개 로드맵이 된다. 무엇이 오고 있는지, 무엇이 일어나고 있는지, 무엇이 일어났는지를 말해주며, 그 모든 줄이 확인 가능하다. Now/Next/Later부터 성과 기반까지 다른 다섯 가지 레이아웃은 샘플 항목과 함께 &lt;a href=&quot;https://changeloop.dev/blog/ko/product-roadmap-examples/&quot;&gt;제품 로드맵 예시&lt;/a&gt;에 실려 있다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;공개 로드맵에는 몇 개의 항목이 있어야 하는가?&lt;/strong&gt;
방어할 수 있는 만큼 최소한으로. 작은 제품이라면 모든 열을 합쳐 열 개 미만이 보통이며, &amp;quot;계획됨&amp;quot;에 서른 개 넘게 있는 것은 로드맵의 옷을 입은 백로그다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;공개 로드맵에 날짜가 있어야 하는가?&lt;/strong&gt;
아니다. 열은 기한을 만들지 않고도 순서를 전달한다. 고객이 날짜를 필요로 한다면, 그것은 로드맵 항목이 아니라 대화의 문제다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;고객이 로드맵 항목에 투표해야 하는가?&lt;/strong&gt;
투표는 무엇이 중요한지가 아니라 누가 나타났는지를 측정한다. 오늘 사용하고 있는 우회 방법을 설명하는 issue의 코멘트 하나가 쉰 표보다 가치가 있으며, 그것은 투표자에게 무언가를 치르게 만드는데, 그것이 핵심이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;취소된 로드맵 항목은 어떻게 되는가?&lt;/strong&gt;
라벨을 제거하고 issue에 이유를 밝혀라. 공개적인 &amp;quot;이것은 하지 않겠다&amp;quot;는 루프의 일부이며, 대부분의 팀이 결코 보내지 않는 메시지다.&lt;/p&gt;
</content:encoded></item><item><title>체인지로그 자동화, 그리고 그 한계에 대하여</title><link>https://changeloop.dev/blog/ko/changelog-automation/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/changelog-automation/</guid><description>수집, 포맷팅, 발행은 자동화해도 좋지만 무엇을 선별하고 어떻게 쓸지는 자동화해선 안 된다. 그 경계선이 어디인지, 옮겨지면 어떻게 되는지 살펴본다.</description><pubDate>Fri, 28 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;체인지로그 자동화는 수집, 분류, 발행을 자동화하고 선별과 문구에서 멈출 때 작동한다. 모든 것을 자동화하면 포맷된 git log를 내보내게 되고, 아무것도 자동화하지 않으면 체인지로그는 릴리스 직전에 기억을 되짚어가며 몰아서 쓰게 된다. 유용한 질문은 어느 부분을 자동화할 것인가이지, 얼마나 자동화할 것인가가 아니다.&lt;/p&gt;
&lt;p&gt;체인지로그 자동화 프로젝트는 두 방향 중 하나로 실패하며, 둘 다 첫 설계 회의에서부터 예측 가능하다. 너무 적게 자동화하면 체인지로그는 누군가 업데이트해야 할 문서가 되고, 그것은 곧 제비뽑기에서 진 사람이 몰아서 업데이트한다는 뜻이다. 너무 많이 자동화하면 포맷된 git log가 된다. 완전하고, 정확하지만, 아무도 읽지 않는다.&lt;/p&gt;
&lt;h2&gt;체인지로그의 어느 부분을 자동화해야 하는가&lt;/h2&gt;
&lt;p&gt;네 단계 중 세 단계다. 수집과 발행은 완전히, 분류는 사람의 재량 개입이 있는 첫 번째 통과로, 선별과 문구는 결코 자동화하지 않는다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;단계&lt;/th&gt;
&lt;th&gt;자동화할 것인가?&lt;/th&gt;
&lt;th&gt;이유&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;수집: 커밋, PR, 티켓으로부터 변경 사항을 목록으로&lt;/td&gt;
&lt;td&gt;완전히&lt;/td&gt;
&lt;td&gt;지루하고, 마감 아래서 빼먹기 쉬우며, 기계가 완벽하게 해낸다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;분류: Added, Fixed, Changed, Deprecated, Removed, Security&lt;/td&gt;
&lt;td&gt;첫 번째 통과 후 사람이 재량 개입&lt;/td&gt;
&lt;td&gt;메타데이터만으로 약 80%가 맞고, 틀린 20%가 바로 중요한 항목들이다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;선별과 문구: 독자에게 무엇을 어떻게 말할지&lt;/td&gt;
&lt;td&gt;결코 하지 않음&lt;/td&gt;
&lt;td&gt;이것이 이 성과물의 가치 전부다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;발행: 페이지, 피드, 이메일, 위젯, Slack&lt;/td&gt;
&lt;td&gt;완전히, 하나의 원천으로부터&lt;/td&gt;
&lt;td&gt;실제로 수작업 노력 대부분이 들어가는 곳&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;수집.&lt;/strong&gt; 변경 사항이 일어나는 곳(커밋, PR, 티켓)에서 그것을 꺼내 목록으로 만드는 것. 이것은 완전히 자동화하라. 사람은 이 일에 서투르고, 지루하며, 마감 아래서 빼먹기 쉬운 단계다. &lt;a href=&quot;https://changeloop.dev/blog/ko/conventional-commits-changelog/&quot;&gt;Conventional commits&lt;/a&gt;나 PR 라벨이 보통의 원재료다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;분류.&lt;/strong&gt; 무언가가 Added, Fixed, Changed, Deprecated, Removed, Security 중 무엇인지 결정하는 것. 커밋 유형이나 PR 라벨로부터 첫 번째 통과를 자동화하고, 사람이 재량으로 뒤집을 수 있게 하라. 메타데이터만으로도 정확도는 약 80퍼센트이며, 틀린 20퍼센트는 정확히 중요한 항목들에 몰려 있다. 모호함이 중요도와 상관관계를 갖기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;선별과 문구.&lt;/strong&gt; 독자에게 무엇을 알려야 하고 어떻게 말해야 하는지를 결정하는 것. &lt;strong&gt;이것은 자동화하지 마라.&lt;/strong&gt; 이것이 이 성과물의 가치 전부다. 나머지 모든 것은 물류에 불과하다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;발행.&lt;/strong&gt; 완성된 항목들을 페이지, 피드, 이메일, 앱 내부 위젯, Slack 채널로 전달하는 것. 완전히, 하나의 원천으로부터 자동화하라. 실제로 수작업 노력 대부분이 들어가는 곳이 여기이며, 그것을 세는 사람은 거의 없다. 이것은 또한 변경을 요청한 사람에게 그것이 출시되었다고 알려줄 수 있는 단계이기도 하며, 그것이 &lt;a href=&quot;https://changeloop.dev/blog/ko/customer-feedback-loop/&quot;&gt;체인지로그 쪽에서 피드백 루프를 닫는 일&lt;/a&gt;의 전부다. 그 단계의 이메일
절반은 &lt;a href=&quot;https://changeloop.dev/blog/ko/product-update-email/&quot;&gt;제품 업데이트 이메일 템플릿&lt;/a&gt;에서 자체적인 형태를 갖는다.&lt;/p&gt;
&lt;p&gt;마지막 요점은 곱씹어볼 가치가 있다. 팀들은 체인지로그를 글쓰기 문제로 여기는 경향이 있고, 그러고 나서 대부분의 시간을 배포에 쓴다. 항목을 이메일 도구에 복사하고, 앱 내부용으로 다시 포맷하고, Slack에 붙여넣고, 문서 페이지를 업데이트하는 것. 글쓰기는 한 시간이다. 복사는 릴리스마다 한 시간씩, 영원히 계속되며, 그것이 바로 기계가 맡아야 할 부분이다.&lt;/p&gt;
&lt;h2&gt;경계선이 옮겨지면 무슨 일이 일어나는가&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;위로 옮기면 git 덤프가 된다.&lt;/strong&gt; 커밋으로부터의 완전한 자동화는 고객 앞에 &lt;code&gt;bump deps&lt;/code&gt;, &lt;code&gt;fix flaky test&lt;/code&gt;, &lt;code&gt;wip&lt;/code&gt;, &lt;code&gt;address review comments&lt;/code&gt;를 내놓게 된다. 이렇게 해본 모든 팀은 결국 필터를 추가했고, 그 필터는 다른 이름 아래 다시 도입된 선별 단계일 뿐이며, 사용성은 더 나빠졌다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;아래로 옮기면 몰아쓰기가 된다.&lt;/strong&gt; 완전히 수동인 수집은 항목이 릴리스 시점에 기억으로부터 쓰인다는 뜻이다. 그것은 &lt;a href=&quot;https://changeloop.dev/blog/ko/keep-a-changelog-implemented/&quot;&gt;Keep a Changelog&lt;/a&gt;가 서두에서 경고하는 바로 그 모드이며, 조용히 악화된다. 체인지로그는 아무도 시간이 없었던 그 주가 오기 직전까지는 관리되고 있는 것처럼 보인다.&lt;/p&gt;
&lt;h2&gt;체인지로그 자동화 파이프라인은 어떤 모습인가&lt;/h2&gt;
&lt;p&gt;네 단계, 그리고 초안이 공개되는 지점에 정확히 하나의 사람 게이트를 둔다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;병합 시점에 PR로부터 초안 항목을 도출한다. 라벨이나 커밋 접두사에서 나온 유형, 첫 초안으로서의 제목, PR로 돌아가는 링크, 기록된 작성자. 이것을 미출시 버킷에 놓는다.&lt;/li&gt;
&lt;li&gt;누구나 언제든 어떤 초안도 편집할 수 있으며, 편집은 저렴하다. 대부분은 한 줄만 다시 쓰인다.&lt;/li&gt;
&lt;li&gt;릴리스를 자르려면 버킷 안의 모든 항목이 편집되었거나 명시적으로 내부용으로 표시되어야 한다. 이 게이트가 설계의 전부다. 이것이 없으면 초안은 바쁜 주에 편집되지 않은 채로 출시된다.&lt;/li&gt;
&lt;li&gt;발행은 출시된 집합으로부터의 팬아웃이다. 공개 페이지, 피드, 이메일, 위젯, Slack 게시물. 하나의 원천, 여러 렌더링, 복사 없음.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;3단계가 사람이 필요한 유일한 곳이며, 초안이 괜찮은 상태라면 릴리스당 약 십 분이 걸린다. 고객의 요청이 관련되어 있을 때, 초안은 그것이 닫는 issue도 함께 운반하며, 그것이 4단계가 요청자에게 알릴 수 있게 해주는 것이다. &lt;a href=&quot;https://changeloop.dev/blog/ko/feature-request-template/&quot;&gt;기능 요망 템플릿&lt;/a&gt;은 그 링크가 살아남도록 설계되어 있다. 이 단계가 더 넓은 릴리스 흐름에서 어디에 놓이는지는 &lt;a href=&quot;https://changeloop.dev/blog/ko/release-management-process/&quot;&gt;릴리스 관리 프로세스&lt;/a&gt;의 주제다.&lt;/p&gt;
&lt;h2&gt;자동화는 여러분의 데이터에 무엇을 요구하는가&lt;/h2&gt;
&lt;p&gt;체인지로그가 Markdown 파일이라면 위의 어느 것도 작동하지 않는다. 파일은 다시 파싱하지 않고는 다섯 개의 표면으로 렌더링될 수 없고, 산문을 파싱하는 것이 바로 제목의 절반만 보여주는 위젯으로 끝나는 이유이기 때문이다.&lt;/p&gt;
&lt;p&gt;항목은 구조화되어야 한다. 유형, 날짜, 버전이나 릴리스 식별자, 대상 독자, 본문, 링크. 그러면 파일, 페이지, 피드, 이메일이 모두 뷰가 된다. 그 구조적인 지점이 도구를 선택하기 전에 제대로 해둘 가치가 있는 유일한 것이다. 나중에 값싸게 바꿔 넣을 수 없는 것이기 때문이다. 필요로 하는 모든 변경에 대해 실제로 항목이 만들어지지 않는 한 이 중 어느 것도 작동하지 않는다. &lt;a href=&quot;https://changeloop.dev/blog/ko/changelog-ci-enforcement/&quot;&gt;CI에서 체인지로그 항목 의무화하기&lt;/a&gt;는 그 단계를 기억에 맡기는 대신, 항목 없는 머지를 파이프라인이 거부하게 만드는 방법을 다룬다.&lt;/p&gt;
&lt;p&gt;우리는 &lt;a href=&quot;https://changeloop.dev/&quot;&gt;changeloop&lt;/a&gt;을 만들고 있으며, 그곳에서 체인지로그는 먼저 피드이고 그다음이 페이지다. 그러니 이것을 공정한 추천이 아니라 이해관계로 읽어주기 바란다. &lt;a href=&quot;https://changeloop.dev/pricing&quot;&gt;요금제&lt;/a&gt;는 카드 없이 시작하는 무료 저장소 하나이며, 그 형태를 보기에는 충분하다. &lt;a href=&quot;https://changeloop.dev/changelog-tools&quot;&gt;체인지로그 도구&lt;/a&gt;는 우리가 경쟁하는 제품을 포함해 그 밖에 무엇이 있는지에 대한 우리의 정리이며, &lt;a href=&quot;https://changeloop.dev/changelog-generator&quot;&gt;체인지로그 생성기&lt;/a&gt;는 파이프라인에 뛰어들기 전에 도출 과정을 보고 싶다면 브라우저에서 수집과 분류 단계를 처리해준다.&lt;/p&gt;
&lt;h2&gt;테스트&lt;/h2&gt;
&lt;p&gt;변경 사항이 병합된 시점부터 여러분의 저장소를 읽지 않는 고객에게 그 변경 사항이 보이게 되는 시점까지의 시간을 분 단위로 세어보라. 그 시간의 대부분이 누군가 도구 사이에서 텍스트를 복사하는 시간이라면, 여러분에게 필요한 자동화는 글쓰기가 아니라 발행에 있다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;AI가 체인지로그를 쓸 수 있는가?&lt;/strong&gt;
초안은 쓸 수 있다. 병합된 pull request를 받은 모델은 대부분의 경우 제목과 본문의 쓸 만한 첫 초안을 만들어내며, 이것은 수집과 분류 단계를 더 잘 해낸 것이다. 독자에게 알려야 할지 말지에 대한 선별, 그리고 최종 문구는 여전히 대상 독자를 아는 사람을 필요로 하며, 그 게이트 없이 초안을 발행하는 파이프라인은 잘못된 단계를 자동화한 것이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;체인지로그 생성기와 체인지로그 자동화의 차이는 무엇인가?&lt;/strong&gt;
생성기는 요청이 있을 때 한 번 커밋을 포맷된 목록으로 바꾼다. 자동화는 병합될 때마다 실행되며, 미출시 버킷을 유지하고, 사람의 검토를 릴리스의 조건으로 삼고, 하나의 원천으로부터 모든 표면에 발행한다. 생성기는 손으로 실행하는 파이프라인의 첫 단계다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;체인지로그는 커밋으로부터 자동화해야 하는가, pull request로부터 자동화해야 하는가?&lt;/strong&gt;
변경 단위가 PR인 pull request로부터다. 제목과 설명은 변경 사항 전체에 대해 한 번 쓰이고, PR은 그것이 닫는 issue를 링크한다. 커밋 기반 도출은 커밋이 단위이고 관례에 따라 쓰일 때 작동한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;자동화가 내부 변경 사항을 발행하지 못하게 하려면 어떻게 해야 하는가?&lt;/strong&gt;
&lt;code&gt;chore&lt;/code&gt;, &lt;code&gt;ci&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt;, &lt;code&gt;refactor&lt;/code&gt;, 의존성 업데이트를 기본적으로 내부용으로 분류하고, 공개로 승격시키는 것을 의도적인 행위로 만들어라. 그 반대의 기본값, 즉 누군가 숨기지 않는 한 공개라는 방식이 &lt;code&gt;bump deps&lt;/code&gt;가 고객에게 도달하는 방식이다.&lt;/p&gt;
</content:encoded></item><item><title>체인지로그 대 릴리스 노트: 무엇이 다른가?</title><link>https://changeloop.dev/blog/ko/changelog-vs-release-notes/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/changelog-vs-release-notes/</guid><description>체인지로그는 무언가를 찾아보는 사람을 위한 계속 이어지는 기록이고, 릴리스 노트는 관심을 가질지 판단하는 사람을 위해 선별한 메시지다.</description><pubDate>Fri, 28 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;체인지로그는 무언가를 찾아보려는 사람을 위해 쓰인, 바뀐 모든 것을 계속 누적해 나가는 기록이다. 릴리스 노트는 이 릴리스가 자신에게 중요한지 판단하려는 사람을 위해 쓰인, 하나의 릴리스에 대한 선별된 메시지다. 그 차이는 서식이 아니라 독자에게 있으며, 대부분의 팀은 둘 다 필요하다. 하나는 참고 자료로, 하나는 발표문으로, 같은 항목들에서 파생된 형태로.&lt;/p&gt;
&lt;p&gt;대부분의 팀은 우연히 둘 중 하나를 갖게 되고, 요청에 의해 나머지 하나를 갖게 된다. 처음에는 어떤 개발자가 무엇이 출시되었는지 기록을 원해서 체인지로그로 시작한다. 몇 달 후 지원팀의 누군가가, 4월부터 이미 살아 있던 기능을 고객들이 왜 몰랐는지 묻고, 그제서야 릴리스 노트가 필요해진다.&lt;/p&gt;
&lt;h2&gt;체인지로그 대 릴리스 노트, 나란히 놓고 비교하기&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;체인지로그&lt;/th&gt;
&lt;th&gt;릴리스 노트&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;독자&lt;/td&gt;
&lt;td&gt;무언가를 찾아보려는 사람&lt;/td&gt;
&lt;td&gt;관심을 가질지 판단하려는 사람&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;범위&lt;/td&gt;
&lt;td&gt;바뀐 모든 것&lt;/td&gt;
&lt;td&gt;이번 릴리스에서 말할 가치가 있는 것&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;주기&lt;/td&gt;
&lt;td&gt;병합마다 또는 릴리스마다, 지속적으로&lt;/td&gt;
&lt;td&gt;릴리스마다, 그리고 발표할 가치가 있는 릴리스만&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;어조&lt;/td&gt;
&lt;td&gt;간결하고 사실적이며, 종종 명령형&lt;/td&gt;
&lt;td&gt;설명적이고, 때로는 설득적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;수명&lt;/td&gt;
&lt;td&gt;영구적이며 몇 년 후에도 읽힌다&lt;/td&gt;
&lt;td&gt;첫 주에 읽히고 그 후 보관된다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;위치&lt;/td&gt;
&lt;td&gt;저장소, 문서 사이트, &lt;code&gt;/changelog&lt;/code&gt; 페이지&lt;/td&gt;
&lt;td&gt;이메일, 앱 내부, 블로그 글, 릴리스 페이지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;실패 방식&lt;/td&gt;
&lt;td&gt;불완전해서 실패한다&lt;/td&gt;
&lt;td&gt;지루하거나, 이미 일이 벌어진 뒤에 도착해서 실패한다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;체인지로그란 무엇인가&lt;/h2&gt;
&lt;p&gt;체인지로그는 최신순으로 정렬되고, 각 항목이 유형(added, changed, deprecated, removed, fixed, security)과 날짜로 표시된, 무엇이 바뀌었는지에 대한 시간순의 거의 완전한 기록이다. 그 독자는 이미 관심을 갖기로 결정한 상태다. 그들은 무언가를 찾고 있다. 어떤 동작이 언제 바뀌었는지, 버그가 고쳐졌는지, 어떤 버전에서 플래그가 도입되었는지. 완전성이 그 모든 가치이며, 그것이 &lt;a href=&quot;https://changeloop.dev/blog/ko/keep-a-changelog-implemented/&quot;&gt;Keep a Changelog&lt;/a&gt; 관례가 단 한 페이지의 대부분을 구조에 쓰고 산문에는 거의 쓰지 않는 이유다.&lt;/p&gt;
&lt;h2&gt;릴리스 노트란 무엇인가&lt;/h2&gt;
&lt;p&gt;릴리스 노트는 하나의 릴리스에 대해 산문으로 쓰인, 선별적인 메시지다. 그 독자는 아직 아무것도 결정하지 않았다. 그들은 이 릴리스가 자신에게 중요한지, 그리고 그것에 대해 무엇을 해야 하는지를 판단하는 중이다. 선별이 그 모든 가치다. 모든 것을 나열하는 릴리스 노트는 문단으로 이루어진 체인지로그일 뿐이며, 무언가를 빼먹은 체인지로그가 독자를 실망시키는 것과 같은 방식으로 독자를 실망시킨다. &lt;a href=&quot;https://changeloop.dev/blog/ko/how-to-write-release-notes/&quot;&gt;릴리스 노트를 쓰는 방법&lt;/a&gt;은 그 선별과 문구에 관한 글이다.&lt;/p&gt;
&lt;h2&gt;체인지로그와 릴리스 노트가 둘 다 필요한가&lt;/h2&gt;
&lt;p&gt;두 독자층이 서로 다른 것을 원하기 시작하면 둘 다 필요하다. 그 전까지는 하나의 성과물이 두 역할을 모두 하는 것이 맞다. 작은 팀들은 각 항목 맨 위에 짧은 문단을 붙인 단일 &lt;code&gt;/changelog&lt;/code&gt; 페이지를 발행하며, 한동안은 그것이 수정 사항을 찾는 개발자와 소식을 훑어보는 고객 모두에게 똑같이 잘 작동한다. 너무 일찍 나누면 유지 관리해야 할 것이 두 개로 늘어나고, 그중 하나는 썩어간다.&lt;/p&gt;
&lt;p&gt;다음과 같은 일이 벌어지기 시작하면 나눌 가치가 생긴다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;체인지로그 항목에 개발자들이 그냥 지나쳐버리는 설명 문단이 늘어난다.&lt;/li&gt;
&lt;li&gt;혹은 반대로, 릴리스 발표문에 의존성 업데이트가 나열되기 시작한다.&lt;/li&gt;
&lt;li&gt;지원팀이 항목들을 이메일에 복사해 넣고 그 과정에서 다시 쓰고 있다.&lt;/li&gt;
&lt;li&gt;누군가 &amp;quot;파괴적 변경만&amp;quot; 요청하는데 그것만 걸러낼 수가 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;마지막 항목이 진짜 신호다. &amp;quot;나에게 영향을 미치는 것이 무엇인지&amp;quot;에 모든 것을 읽지 않고는 아무도 답할 수 없다면, 하나의 성과물이 두 역할을 서투르게 하고 있는 것이다.&lt;/p&gt;
&lt;h2&gt;하나의 원천, 두 가지 뷰&lt;/h2&gt;
&lt;p&gt;흔한 실수는 이 둘을 두 개의 문서로 취급하는 것이다. 이것들은 같은 변경 사항 집합에 대한 두 가지 뷰다.&lt;/p&gt;
&lt;p&gt;체인지로그는 진행하면서 작성하라. 의미 있는 변경마다 하나의 항목을, 각각 fixed, added, changed, removed, deprecated, security 중 무엇인지 태그를 붙여서. 항목을 짧게 유지해서 그것을 쓰는 일 자체가 하나의 결정이 되지 않도록 하라. 그러고 나서 릴리스 시점에 릴리스 노트는 선별이자 다시 쓰기가 된다. 사람에게 중요한 항목들을 골라, 그것이 누군가로 하여금 할 수 있게 해주는 일에 따라 묶고, 이유를 맨 위에 둔다.&lt;/p&gt;
&lt;p&gt;여기에는 실용적인 결과가 하나 따라온다. 체인지로그가 원천이라면, 그것은 손으로 관리하는 페이지가 아니라 구조화된 데이터여야 한다. 항목은 유형, 날짜, 버전, 그리고 누구를 위한 것인지 말하는 방법을 가져야 한다. 그것이 갖춰지면 공개 페이지, 앱 내부 위젯, RSS 또는 JSON 피드는 하나의 것에 대한 세 가지 렌더링이 되고, 고객에게 가는 길에 아무도 아무것도 다시 쓰지 않는다. 릴리스 노트 이메일도 이메일을 보내는 도구가 무엇이든 거기서 같은 항목을 인용할 수 있다. &lt;a href=&quot;https://changeloop.dev/blog/ko/changelog-automation/&quot;&gt;체인지로그 자동화&lt;/a&gt;는 이 단계들 중 어느 것을 기계가 맡아야 하는지에 관한 글이다. 그것이 체인지로그를 페이지가 아니라 피드로 다루어야 한다는 논거의 전부다. 그리고 솔직히 말해 그것이 바로 우리가 만들고 있는 것이기도 하니, 이 글은 중립적인 조사가 아니라 이해관계가 있는 입장으로 읽어주기 바란다.&lt;/p&gt;
&lt;h2&gt;시간이 하나만 있다면&lt;/h2&gt;
&lt;p&gt;체인지로그를 써라. 항목당 비용이 더 낮고, 쓰는 그 날부터 유용하며, 릴리스 노트는 나중에 그것으로부터 도출할 수 있다. 그 반대는 성립하지 않는다. 열두 통의 발표 이메일로부터 일 년치 변경 사항을 재구성할 수는 없으며, 사람들은 그것을 요구할 것이다.&lt;/p&gt;
&lt;p&gt;도출이 계속 가능하도록 고정된 형식으로 유지하라. 우리의 &lt;a href=&quot;https://changeloop.dev/changelog-examples&quot;&gt;체인지로그 예시&lt;/a&gt; 페이지는 이것을 잘 해내는 팀들의 항목을 모아 놓았고, &lt;a href=&quot;https://changeloop.dev/release-notes-template&quot;&gt;릴리스 노트 템플릿&lt;/a&gt;은 우리가 항목들의 집합을 보낼 가치가 있는 무언가로 바꿀 때 사용하는 형식이다.&lt;/p&gt;
&lt;h2&gt;이름 짓기에 대한 한마디&lt;/h2&gt;
&lt;p&gt;이것은 표준화되어 있지 않으며, &amp;quot;release notes&amp;quot;가 계속 이어지는 목록을 가리키는 데 쓰이고 &amp;quot;changelog&amp;quot;가 분기별 발표를 가리키는 데 쓰이는 경우도 발견하게 될 것이다. 단어를 두고 논쟁할 가치는 없다. 여러분의 각 성과물이 두 역할 중 어느 것을 하고 있는지 정하고, 팀에서 이미 부르는 대로 이름을 붙이고, 어느 쪽도 조용히 둘 다 하고 있지는 않은지 확인하라.&lt;/p&gt;
&lt;p&gt;결과가 어느 표면에 안착할지는 별도의 결정이며, &lt;a href=&quot;https://changeloop.dev/blog/ko/changelog-page/&quot;&gt;체인지로그 페이지 만드는 법&lt;/a&gt;에서
다룬다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;체인지로그와 릴리스 노트는 같은 것인가?&lt;/strong&gt;
아니다. 체인지로그는 무언가를 찾아보려는 사람들이 읽는 완전한 기록이고, 릴리스 노트는 관심을 가질지 판단하려는 사람들이 읽는 선별된 발표문이다. 같은 변경 사항이 둘 다에 등장하지만, 각 독자에 맞게 다르게 표현된다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;릴리스 노트를 체인지로그로부터 생성할 수 있는가?&lt;/strong&gt;
그렇다. 그것이 옳은 방향이다. 사람이 관심을 가질 항목들을 선별하고, 결과별로 묶고, 헤드라인을 다시 써라. 반대 방향, 즉 발표문으로부터 체인지로그를 재구성하는 것은 발표문이 빼먹은 모든 것을 잃어버린다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;체인지로그는 어디에 있어야 하는가?&lt;/strong&gt;
저장소 없이도 독자가 닿을 수 있는, 영구적이고 링크 가능한 곳. &lt;code&gt;/changelog&lt;/code&gt; 페이지, 문서 사이트, 또는 여러 곳에서 렌더링되는 피드. &lt;code&gt;CHANGELOG.md&lt;/code&gt; 하나만으로는 기여자에게는 닿지만 고객에게는 닿지 않는다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;체인지로그에 내부 변경 사항을 포함해야 하는가?&lt;/strong&gt;
그렇다. 맨 아래에 한 줄씩. 체인지로그는 완전한 기록이다. 릴리스 노트에도 짧은 마지막 섹션으로 남겨둘 수 있다. 단, 독자가 알아챌 변경 사항이 먼저 와야 한다.&lt;/p&gt;
</content:encoded></item><item><title>Conventional commits에서 체인지로그로</title><link>https://changeloop.dev/blog/ko/conventional-commits-changelog/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/conventional-commits-changelog/</guid><description>Conventional commits는 체인지로그를 도출 가능하게 하지만 읽기 쉽게 만들지는 못한다. 이 관례가 사주는 것과 한계, 그 간극을 메우는 법을 살펴본다.</description><pubDate>Fri, 28 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Conventional commits는 체인지로그에 세 가지를 공짜로 준다. 각 변경 사항의 유형, 그것이 건드린 시스템의 부분, 그리고 무언가를 망가뜨리는지 여부다. 그 외에는 아무것도 주지 않는다. 문구, 그룹화, 선별, 즉 체인지로그 그 자체는 전적으로 열려 있는 상태로 남으며, 그렇지 않은 척하는 파이프라인은 포맷된 git log를 내보내게 된다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;feat(exports): add CSV column selection
fix(auth): reject expired refresh tokens
chore(deps): bump node-pg to 8.11
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://www.conventionalcommits.org/&quot;&gt;Conventional Commits&lt;/a&gt; 형식의 세 커밋이다. 이것들로부터 기계는 하나는 기능이고, 하나는 수정이고, 하나는 정리 작업이며, 각각이 시스템의 어느 부분을 건드렸는지를 알려줄 수 있다. 이것은 정말로 유용하며, 이 관례의 약속 전부이기도 하다. 사람이 아닌 무언가가 읽을 수 있는 커밋 히스토리. 실수는 이것이 체인지로그를 만들어준다고 생각하는 것이다. 이것이 주는 것은 원재료다.&lt;/p&gt;
&lt;h2&gt;이 관례는 무엇을 규정하는가&lt;/h2&gt;
&lt;p&gt;유형, 선택적인 범위, 그리고 설명: &lt;code&gt;type(scope): description&lt;/code&gt;. 유형은 관례적으로 &lt;code&gt;feat&lt;/code&gt;, &lt;code&gt;fix&lt;/code&gt;, &lt;code&gt;chore&lt;/code&gt;, &lt;code&gt;docs&lt;/code&gt;, &lt;code&gt;refactor&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt;, &lt;code&gt;perf&lt;/code&gt;, &lt;code&gt;build&lt;/code&gt;, &lt;code&gt;ci&lt;/code&gt;다. 파괴적 변경을 표시하는 것은 두 가지다. 콜론 앞의 &lt;code&gt;!&lt;/code&gt;, 또는 &lt;code&gt;BREAKING CHANGE:&lt;/code&gt; 푸터. 도구는 마이너와 패치 버전 증가를 위해 &lt;code&gt;feat&lt;/code&gt;와 &lt;code&gt;fix&lt;/code&gt;에, 메이저를 위해 파괴적 변경 표시에 의존한다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;커밋이 주는 것&lt;/th&gt;
&lt;th&gt;체인지로그가 필요로 하는 것&lt;/th&gt;
&lt;th&gt;누가 그 간극을 채우는가&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;code&gt;feat&lt;/code&gt; / &lt;code&gt;fix&lt;/code&gt; / &lt;code&gt;chore&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Added / Fixed / 내부용&lt;/td&gt;
&lt;td&gt;매핑, 자동&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(scope)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;독자가 알아볼 수 있는 그룹화&lt;/td&gt;
&lt;td&gt;사람, 범위당 한 번&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;!&lt;/code&gt; 또는 &lt;code&gt;BREAKING CHANGE:&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;누가, 언제까지, 무엇을 해야 하는지&lt;/td&gt;
&lt;td&gt;사람, 매번&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;리뷰어를 위해 쓰인 설명&lt;/td&gt;
&lt;td&gt;고객을 위해 쓰인 결과&lt;/td&gt;
&lt;td&gt;사람, 항목마다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;커밋 하나&lt;/td&gt;
&lt;td&gt;여러 커밋일 수 있는 변경 사항 하나&lt;/td&gt;
&lt;td&gt;스쿼시 규칙, 또는 사람&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;이 표시는 도구에게 알려줄 뿐 호출자에게는 알려주지 않는다. 그것은 &lt;a href=&quot;https://changeloop.dev/blog/ko/api-deprecation/&quot;&gt;API를 비추천 처리하는 방법&lt;/a&gt;과 &lt;a href=&quot;https://changeloop.dev/blog/ko/breaking-changes/&quot;&gt;파괴적 변경이란 무엇인가&lt;/a&gt;의 주제다. 이것은 작은 스펙이며, 거기서 아무것도 생성하지 않더라도 따를 가치가 있다. 커밋마다 하나의 결정을 강제하기 때문이다. 이것은 사용자가 보는 변경인가, 아닌가.&lt;/p&gt;
&lt;h2&gt;Conventional commits는 어디서 멈추는가&lt;/h2&gt;
&lt;p&gt;문장에서 멈춘다. 이 관례가 포착하는 모든 것은 변경 사항에 대한 메타데이터이고, 변경 사항 그 자체는 여전히 리뷰어의 어휘로 서술되어 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;커밋 메시지는 리뷰어를 위해 쓰인다.&lt;/strong&gt; &lt;code&gt;fix(auth): reject expired refresh tokens&lt;/code&gt;는 정확하지만 고객에게는 아무것도 말해주지 않는다. 체인지로그의 독자가 원하는 것은 &amp;quot;세션이 실제로 만료되었을 때만 로그아웃되며, 간헐적인 401은 더 이상 보이지 않습니다&amp;quot;다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;범위는 내부용이다.&lt;/strong&gt; &lt;code&gt;exports&lt;/code&gt;, &lt;code&gt;auth&lt;/code&gt;, &lt;code&gt;ingest&lt;/code&gt;는 모듈 이름이다. 안정적이라서 그룹화에는 좋지만, 코드베이스 밖의 누구에게도 무의미하다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;하나의 변경 사항은 흔히 여러 커밋이다.&lt;/strong&gt; 열한 개의 커밋에 걸쳐 병합된 기능은 열한 개의 항목을 만들고, 그중 열 개는 잡음이며, 그것을 숨기려고 스쿼시하면 리뷰 히스토리를 잃는다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;chore&lt;/code&gt;는 분류가 아니라 쓰레기통이다.&lt;/strong&gt; 의존성 업데이트, CI 변경, 이름 변경이 모두 그곳에 떨어지며, 그중 일부는 사용자에게 중요하지만 대부분은 그렇지 않다.&lt;/p&gt;
&lt;p&gt;즉, 이 관례는 유형, 범위, 파괴적 여부를 공짜로 주고, 문구, 그룹화, 선별은 전적으로 열어둔다. 이 세 가지가 바로 체인지로그다.
&lt;a href=&quot;https://changeloop.dev/blog/ko/changelog-entry-ownership/&quot;&gt;체인지로그 항목은 실제로 누가 책임지는가&lt;/a&gt;는 그 문구,
그룹화, 선별을 누가 맡아야 하는지를 다룬다. 관례 자체는 그것에 대해 아무런 의견도 갖고
있지 않기 때문이다.&lt;/p&gt;
&lt;h2&gt;Conventional commits로부터 체인지로그를 어떻게 생성하는가&lt;/h2&gt;
&lt;p&gt;두 개의 층으로, 그리고 두 번째 층은 필수여야 한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;첫 번째 층, 자동.&lt;/strong&gt; 병합 시점에 커밋으로부터 초안 항목을 도출한다. 유형을 체인지로그 유형으로 매핑하고(&lt;code&gt;feat&lt;/code&gt;는 Added로, &lt;code&gt;fix&lt;/code&gt;는 Fixed로, 파괴적 변경 표시는 플래그를 단 Changed로), 범위는 텍스트가 아니라 메타데이터로 유지하고, PR로의 링크를 단다. 이것을 &lt;a href=&quot;https://changeloop.dev/blog/ko/keep-a-changelog-implemented/&quot;&gt;Keep a Changelog&lt;/a&gt;가 요구하는 Unreleased 섹션에 놓는다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;두 번째 층, 사람, 그리고 필수.&lt;/strong&gt; 릴리스가 나가기 전에, 모든 초안 항목은 사용자의 어휘로 한 줄 다시 쓰이거나, 내부용으로 표시되어 공개 뷰에서 빠져야 한다. 이것이 사람들이 건너뛰려고 하는 단계이며, 이것을 건너뛰는 것이 diff처럼 읽히는 체인지로그를 만들어낸다.&lt;/p&gt;
&lt;p&gt;중요한 설계상의 세부 사항은 두 번째 층이 파이프라인에서 선택 사항이 아니라는 점이다. 편집되지 않은 초안으로 릴리스를 자를 수 있다면, 모두가 바쁜 그 주에 그렇게 될 것이다. 어떤 단계가 기계의 것이고 어떤 단계가 사람의 것인지가 &lt;a href=&quot;https://changeloop.dev/blog/ko/changelog-automation/&quot;&gt;체인지로그 자동화&lt;/a&gt;의 전부다.&lt;/p&gt;
&lt;p&gt;릴리스를 자르는 것은 또한 git 태그, 릴리스, 그리고 이 체인지로그 항목이 서로 맞아떨어지거나 동기화에서 벗어나기 시작하는 순간이다; &lt;a href=&quot;https://changeloop.dev/blog/ko/git-tags-releases-changelog/&quot;&gt;git 태그, 릴리스, 그리고 당신의 체인지로그&lt;/a&gt;가 셋을 동기화된 상태로 유지하는 방법을 다룬다.&lt;/p&gt;
&lt;h2&gt;세 가지 함정&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;스쿼시 병합이 푸터를 먹어버린다.&lt;/strong&gt; 여러분의 플랫폼이 PR 제목을 메시지로 삼아 스쿼시한다면, 그 브랜치 안의 커밋에 있던 &lt;code&gt;BREAKING CHANGE:&lt;/code&gt; 푸터는 사라지고, 여러분의 도구는 조용히 그 파괴적 변경을 보지 못하게 된다. 여러분의 스쿼시 템플릿이 실제로 무엇을 유지하는지 확인하라.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;되돌린 커밋이 유령 항목을 만든다.&lt;/strong&gt; 다음 날 되돌려진 &lt;code&gt;fix&lt;/code&gt;는, 도출 과정이 되돌림을 반영하지 않는 한, 결코 출시되지 않은 무언가에 대한 항목을 생성한다. 대부분의 도구는 그렇게 하지 않는다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;버전 증가와 체인지로그가 어긋난다.&lt;/strong&gt; 버전이 커밋으로부터 계산되고 체인지로그가 나중에 손으로 쓰인다면, 이 둘은 약 두 번의 릴리스 안에 어긋난다. 둘 다 같은 패스에서 계산하거나, 둘 중 하나가 틀렸다는 것을 받아들여라.&lt;/p&gt;
&lt;h2&gt;파이프라인 없이 기계적인 부분만 원한다면&lt;/h2&gt;
&lt;p&gt;우리의 &lt;a href=&quot;https://changeloop.dev/changelog-generator&quot;&gt;체인지로그 생성기&lt;/a&gt;는 브라우저에서 도출 단계를 수행한다. 커밋을 붙여넣으면 그룹화되고 유형이 붙은 항목이 나온다. 의도적으로 결정론적이고 완전히 클라이언트 측에서 동작하므로, 붙여넣은 커밋이 여러분의 기기를 벗어나는 일이 없다. 이는 비공개 저장소의 메시지일 때 중요하다. 이것은 수집 절반을 정직하게 처리하고 두 번째 층을 흉내 내려는 시도는 하지 않는다. 두 번째 층은 판단의 문제이며, 그것을 흉내 내는 도구는 정확히 이 글이 반대하는 그 체인지로그를 만들어내기 때문이다.&lt;/p&gt;
&lt;p&gt;파이프라인 버전에 대해서는 &lt;a href=&quot;https://changeloop.dev/changelog-tools&quot;&gt;체인지로그 도구&lt;/a&gt;가 무엇이 존재하는지를 다룬다.&lt;/p&gt;
&lt;h2&gt;요약&lt;/h2&gt;
&lt;p&gt;Conventional commits는 &amp;quot;이것이 어떤 종류의 변경인가&amp;quot;에 신뢰성 있고 저렴하게 답한다. &amp;quot;사람들에게 무엇을 말해야 하는가&amp;quot;에는 답하지 않으며, 커밋 메시지 위에 아무리 도구를 쌓아도 그것은 답이 되지 않는다. 그 정보가 애초에 커밋 메시지 안에 존재한 적이 없기 때문이다. 다시 쓰기를 위한 예산을 확보하라.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Conventional commits는 체인지로그를 자동으로 생성하는가?&lt;/strong&gt;
초안은 자동으로 생성한다. 유형이 붙고, 범위가 지정되고, 링크가 걸린 항목들이다. 고객을 위한 문구, 그룹화, 무엇을 뺄지에 대한 결정은 여전히 사람을 필요로 하며, 그 단계를 건너뛰는 파이프라인은 커밋 메시지를 그대로 발행하게 된다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;어떤 conventional commit 유형이 체인지로그에 나타나는가?&lt;/strong&gt;
&lt;code&gt;feat&lt;/code&gt;와 &lt;code&gt;fix&lt;/code&gt;는 항상 Added와 Fixed로 나타난다. &lt;code&gt;perf&lt;/code&gt;는 보통 Changed로 나타난다. &lt;code&gt;chore&lt;/code&gt;, &lt;code&gt;docs&lt;/code&gt;, &lt;code&gt;refactor&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt;, &lt;code&gt;build&lt;/code&gt;, &lt;code&gt;ci&lt;/code&gt;는 기본적으로 내부용이며, 사람이 그중 하나를 승격시켰을 때만 나타난다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conventional commits는 파괴적 변경을 어떻게 표시하는가?&lt;/strong&gt;
유형이나 범위 뒤의 &lt;code&gt;!&lt;/code&gt;(&lt;code&gt;feat(api)!: ...&lt;/code&gt;), 또는 커밋 본문의 &lt;code&gt;BREAKING CHANGE:&lt;/code&gt; 푸터. 스쿼시 병합이 PR 제목만 남긴다면 둘 다 사라진다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;체인지로그를 자동화하는 데 conventional commits가 필요한가?&lt;/strong&gt;
필요 없다. PR 라벨, PR 템플릿, issue 링크는 pull request로 병합하는 팀에게 같은 메타데이터를 전달한다. Conventional commits는 변경 단위가 커밋일 때 가장 저렴한 선택지다.&lt;/p&gt;
</content:encoded></item><item><title>실제로 읽히는 릴리스 노트를 쓰는 방법</title><link>https://changeloop.dev/blog/ko/how-to-write-release-notes/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/how-to-write-release-notes/</guid><description>버그 수정 및 성능 개선이라는 문구만으로는 릴리스 노트라고 할 수 없다. 모든 항목이 답해야 하는 하나의 질문과 실제 사례의 고치기 전후를 보여준다.</description><pubDate>Fri, 28 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;사람들이 실제로 읽는 릴리스 노트를 쓰려면, 항목마다 하나의 질문에 답하라. 독자가 이전에는 할 수 없었지만 지금은 할 수 있게 된 것은 무엇이며, 그것에 대해 독자가 해야 할 일은 무엇인가. 기한이 있는 내용은 항상 맨 앞에 두고, 누가 영향을 받는지 이름을 밝히고, 정말로 아무것도 할 필요가 없다면 &amp;quot;조치가 필요 없습니다&amp;quot;라고 말하고, 특별히 할 말이 없는 릴리스는 건너뛰어라. 이 페이지의 나머지 내용은 모두 이 규칙을 적용한 것이다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;버그 수정 및 성능 개선.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;모든 제품이 이런 문구를 내보낸 적이 있다. 원인은 게으름인 경우가 드물다. 이것은 릴리스 노트를 내부 시점에서, 즉 이미 두 주 동안 diff 속에서 살아온 사람이, 낯선 사람이라면 어느 부분에 신경을 쓸지 더는 알아차리지 못하는 상태에서 쓸 때 나오는 결과다. 더 나은 어조로는 이 문제가 고쳐지지 않는다. 질문에 답하는 것만이 고친다.&lt;/p&gt;
&lt;h2&gt;릴리스 노트에는 무엇을 포함해야 하는가&lt;/h2&gt;
&lt;p&gt;릴리스 노트는 언급할 가치가 있는 각 변경 사항에 대해, 독자가 이제 무엇을 할 수 있는지, 누구에게 해당되는지, 그것에 대해 무엇을 해야 하는지(&amp;quot;아무것도 없음&amp;quot;을 포함해서), 그리고 기한이 있는 항목이라면 언제부터 적용되는지를 포함해야 한다. 내부 티켓 번호, 팀만 아는 컴포넌트 이름, 그리고 헤드라인 역할만 하는 버전 번호는 포함하지 않아야 한다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;포함할 것&lt;/th&gt;
&lt;th&gt;제외할 것&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;독자의 언어로 표현한 결과&lt;/td&gt;
&lt;td&gt;팀의 언어로 표현한 구현 방식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;요금제, 역할, API 버전 등으로 명시한 영향 대상&lt;/td&gt;
&lt;td&gt;&amp;quot;일부 사용자&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;필요한 조치, 또는 &amp;quot;조치가 필요 없음&amp;quot;&lt;/td&gt;
&lt;td&gt;침묵. 독자는 침묵을 최악의 경우로 채운다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;기한이 있는 항목의 날짜&lt;/td&gt;
&lt;td&gt;날짜 대신 내세운 버전 번호&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;설명 문서로의 링크&lt;/td&gt;
&lt;td&gt;pull request로의 링크&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;사람들이 신고한 수정 사항과 완화된 제한&lt;/td&gt;
&lt;td&gt;내부 티켓 id&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;하단에 한 줄씩 정리한 지루한 항목들&lt;/td&gt;
&lt;td&gt;소식과 뒤섞인 지루한 항목들&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;릴리스 노트와 &lt;a href=&quot;https://changeloop.dev/blog/ko/changelog-vs-release-notes/&quot;&gt;체인지로그 항목&lt;/a&gt;의 구분이 있기에 이 목록이 가능해진다. 체인지로그는 모든 것을 담아 두므로, 노트는 무언가를 빼도 괜찮다. 항목 유형별 주석 달린 샘플은 &lt;a href=&quot;https://changeloop.dev/blog/ko/release-notes-examples/&quot;&gt;릴리스 노트 예시&lt;/a&gt;에 모아 두었다.&lt;/p&gt;
&lt;h2&gt;모든 항목이 답해야 하는 질문&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;독자가 이전에는 할 수 없었지만 지금은 할 수 있게 된 것은 무엇이며, 그것에 대해 무엇을 해야 하는가?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;어떤 항목이 이 질문에 답할 수 없다면, 그것은 릴리스 노트가 아니라 체인지로그에 속한다. 두 부분 모두 중요하다. 앞부분은 가치이고, 뒷부분은 팀들이 흔히 잊는 부분이며, 빠졌을 때 지원 티켓을 만들어내는 부분이다.&lt;/p&gt;
&lt;p&gt;뒷부분이 실제로 일을 하는 두 가지 예시다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;quot;기존 웹훅은 11월 1일까지 계속 작동합니다. 그 이후에는 서명되지 않은 페이로드가 거부됩니다.&amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;quot;조치가 필요 없습니다. 기존 내보내기 파일은 다음에 열 때 자동으로 다시 인코딩됩니다.&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;두 번째 예시는 &amp;quot;조치가 필요 없습니다&amp;quot;라고 명시적으로 말한다. 그 문장은 매번 써넣을 가치가 있다. 그것을 찾지 못한 독자는 최악의 상황을 가정하기 때문이다.&lt;/p&gt;
&lt;h2&gt;릴리스 노트는 어떤 순서로 배치해야 하는가&lt;/h2&gt;
&lt;p&gt;시스템의 어느 부분이 바뀌었는지가 아니라, 독자에게 미치는 결과에 따라 순서를 정하라. API, 대시보드, 모바일, 인프라로 묶는 것은 여러분의 조직도이지, 독자의 문제가 아니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;파괴적 변경과 기한이 있는 모든 것.&lt;/strong&gt; 작은 것이라도 항상 맨 먼저 둔다. 독자가 한 줄만 읽고 멈춘다면, 이 줄은 반드시 읽었어야 할 줄이다. 기한이 서비스 종료일이라면, 그 항목은 &lt;a href=&quot;https://changeloop.dev/blog/ko/api-deprecation/&quot;&gt;비추천 공지&lt;/a&gt;처럼 읽혀야 한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;독자가 원할 만한 새로운 것.&lt;/strong&gt; 문단마다 하나씩, 첫 절에 결과를 담는다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;더 나아진 것.&lt;/strong&gt; 신고되었던 수정 사항, 완화된 제한, 느렸던 부분들.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;그 밖의 모든 것, 목록으로.&lt;/strong&gt; 의존성 업데이트, 내부 리팩터링, 소소한 문구 변경. 한 줄씩. 이 섹션을 읽는 사람은 거의 없지만, 그래도 있어야 한다. 그것을 찾는 사람에게는 정말로 필요한 정보이기 때문이다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;다시 쓰기&lt;/h2&gt;
&lt;p&gt;이전:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;v4.2.0&lt;/strong&gt; &lt;code&gt;POST /exports&lt;/code&gt; 엔드포인트가 부하 상황에서 간헐적으로 500을 반환하던 문제를 수정했습니다. export worker를 리팩터링했습니다. &lt;code&gt;node-pg&lt;/code&gt;를 8.11로 업데이트했습니다. CSV serializer의 오류 처리를 개선했습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이후:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;대규모 계정에서 더 이상 내보내기가 실패하지 않습니다.&lt;/strong&gt;
약 5만 행이 넘는 계정은 내보내기를 시작할 때 500 오류를 받을 수 있었고, 월말에 특히 자주 발생했습니다. 이제 수정되었고, 크기와 무관하게 모든 내보내기가 실패하는 대신 스스로 재시도합니다. 조치가 필요 없으며, 지난 한 주 동안 실패한 내보내기는 그저 다시 실행하기만 하면 됩니다.&lt;/p&gt;
&lt;p&gt;4.2.0의 다른 변경 사항: &lt;code&gt;node-pg&lt;/code&gt; 8.11, 더 명확해진 CSV serializer 오류 메시지.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;같은 릴리스다. 두 번째 버전은 영향을 받은 계정, 가장 심했던 시기, 무엇이 바뀌었는지, 그리고 무엇을 해야 하는지를 명시한다. 의존성 업데이트가 사라진 것이 아니라, 그저 헤드라인이 되기를 멈췄을 뿐이다. &lt;a href=&quot;https://changeloop.dev/blog/ko/release-notes-best-practices/&quot;&gt;릴리스 노트 모범 사례&lt;/a&gt; 글에는 이 다시 쓰기가 따르고 있는 나머지 규칙들이, 각각 건너뛸 때 어떤 대가가 따르는지와 함께 담겨 있다.&lt;/p&gt;
&lt;h2&gt;삭제할 가치가 있는 것들&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&amp;quot;저희는 발표하게 되어 매우 기쁩니다.&amp;quot;&lt;/strong&gt; 독자는 아직 기쁘지 않다. 그 기쁨은 다음 문장에서 스스로 얻어내야 한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;내부 티켓 번호.&lt;/strong&gt; &lt;code&gt;PROJ-4471&lt;/code&gt;은 여러분의 트래커 밖에서는 아무 의미가 없다. 참조가 필요하다면 문서 페이지를 링크하라.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;팀만 사용하는 컴포넌트 이름.&lt;/strong&gt; &amp;quot;ingest pipeline&amp;quot;의 이름을 바꿨다면 &amp;quot;가져오기&amp;quot;라고 말하라.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;유일한 헤드라인 역할을 하는 버전 번호.&lt;/strong&gt; &lt;code&gt;v4.2.0&lt;/code&gt;은 요약이 아니라 정리용 라벨일 뿐이다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;아무도 방문한 적 없는 설정 페이지의 스크린샷.&lt;/strong&gt; 실제로 바뀐 것이 사용되는 모습을 보여줘라.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;릴리스 노트는 얼마나 자주 발행해야 하는가&lt;/h2&gt;
&lt;p&gt;일정에 맞춰서가 아니라, 무언가 일어났을 때 발행하라. 릴리스마다 도착하는 노트는 모두가 그것을 무시하도록 훈련시킨다. 무언가 일어났을 때 도착하는 노트는 열어보게 된다. 아무 노트도 없이 릴리스를 내보내고, 그 항목들을 읽을 가치가 있는 헤드라인이 나올 다음 묶음으로 넘기는 것도 괜찮고, 대개는 그것이 맞다.&lt;/p&gt;
&lt;p&gt;체인지로그는 여전히 그 모든 것을 기록한다. 그것이 역할 분담이다. 체인지로그는 완전하고, 노트는 선별적이다. 체인지로그를 진행하는 동안 구조화된 상태로 유지한다면, 노트를 쓰는 일은 고고학이 아니라 선별과 다시 쓰기가 된다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://changeloop.dev/release-notes-template&quot;&gt;릴리스 노트 템플릿&lt;/a&gt;은 우리가 선별 단계에서 사용하는 형식이며, &lt;a href=&quot;https://changeloop.dev/changelog-examples&quot;&gt;체인지로그 예시&lt;/a&gt;는 그 체인지로그가 충분히 훌륭해서 노트를 도출할 수 있는 팀들의 항목들을 모아 놓았다.&lt;/p&gt;
&lt;p&gt;이 모든 것은 완전히 통제할 수 있는 페이지, 길이 제한이 없고 링크가 작동하는 페이지를 전제로 한다. &lt;a href=&quot;https://changeloop.dev/blog/ko/mobile-app-release-notes/&quot;&gt;모바일 앱 릴리스 노트&lt;/a&gt;는 그 표면이 앱스토어나 플레이스토어 목록일 때 무엇이 달라지는지를 다룬다.
&lt;a href=&quot;https://changeloop.dev/blog/ko/emergency-release-notes/&quot;&gt;긴급 릴리스 노트&lt;/a&gt;는 또 다른 예외를 다룬다. 평소의 작성
과정을 따를 시간이 전혀 남지 않았을 때 무엇이 달라지는지다.&lt;/p&gt;
&lt;h2&gt;발행 전 테스트 하나&lt;/h2&gt;
&lt;p&gt;2주간 휴가를 다녀와서 40초밖에 시간이 없는 사람이라고 생각하고 노트를 읽어보라. 그 시간 안에 자신에게 무언가 요구되는 것이 있는지 없는지를 알 수 없다면, 그 노트는 아무리 정확해도 아직 완성된 것이 아니다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;릴리스 노트는 얼마나 길어야 하는가?&lt;/strong&gt;
결과에 영향을 미치는 변경 사항이 필요로 하는 만큼, 그 이상은 안 된다. 파괴적 변경 하나와 개선 사항 두 개가 있는 릴리스는 세 문단이면 충분하다. 조용한 릴리스를 부풀려 그럴듯하게 보이려는 것이야말로 독자가 노트를 건너뛰도록 가르치는 방법이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;릴리스 노트는 누가 써야 하는가?&lt;/strong&gt;
변경 사항을 이해하는 사람이 쓰고, 그것을 모르는 사람이 편집해야 한다. 엔지니어는 무엇이 바뀌었는지 알고, 편집자는 낯선 사람이 무엇을 오해할지 안다. 엔지니어가 아직 기억하고 있는 병합 시점에 항목을 써두는 관행이 이 작업을 저렴하게 만든다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;릴리스 노트에는 버그 수정도 포함해야 하는가?&lt;/strong&gt;
그렇다. 누군가 신고했거나 직접 겪은 것이라면. 원인이 아니라 독자가 목격한 증상을 서술하라. &amp;quot;5만 행이 넘는 내보내기가 실패했습니다&amp;quot;는 독자가 알아보는 버그 수정이지만, &amp;quot;export worker의 경쟁 조건을 수정했습니다&amp;quot;는 커밋 메시지다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;릴리스 노트와 체인지로그의 차이는 무엇인가?&lt;/strong&gt;
체인지로그는 완전하고 계속 이어지는 기록이며, 릴리스 노트는 아직 관심을 가질지 결정하지 않은 사람들을 위해 쓰인, 하나의 릴리스에 대한 선별된 메시지다. 더 자세한 답은 &lt;a href=&quot;https://changeloop.dev/blog/ko/changelog-vs-release-notes/&quot;&gt;체인지로그 대 릴리스 노트&lt;/a&gt;에 있다.&lt;/p&gt;
</content:encoded></item><item><title>Keep a Changelog, 실제로 적용해 보니</title><link>https://changeloop.dev/blog/ko/keep-a-changelog-implemented/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/keep-a-changelog-implemented/</guid><description>Keep a Changelog 명세는 한 페이지이고 읽는 데 십 분도 걸리지 않지만, 구현하면서 대부분의 팀이 어긋난다. 명세가 말하는 것과 열어둔 것, 틀린 곳을 살펴본다.</description><pubDate>Fri, 28 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Keep a Changelog는 &lt;code&gt;CHANGELOG.md&lt;/code&gt;를 위한 한 페이지짜리 관례다. 최신 버전을 맨 위에, 버전마다 번호와 ISO 날짜를 가진 섹션 하나씩, 여섯 가지 유형(Added, Changed, Deprecated, Removed, Fixed, Security) 아래 묶인 항목들, 그리고 릴리스 사이의 항목들을 위한 맨 위의 Unreleased 섹션. 이것을 인용하는 대부분의 팀은 그중 약 삼분의 이만 구현하며, 그들이 빼먹는 삼분의 일이 바로 사용자를 보호하는 삼분의 일이다.&lt;/p&gt;
&lt;p&gt;Olivier Lacan은 2014년에 &lt;a href=&quot;https://keepachangelog.com/&quot;&gt;Keep a Changelog&lt;/a&gt;를 발표하면서, 대부분의 소프트웨어 관련 글보다 더 잘 버텨온 한 문장을 남겼다. &lt;em&gt;친구들이 체인지로그에 git log를 그대로 쏟아붓게 두지 마라.&lt;/em&gt; 십 년이 지난 지금, 이것은 소프트웨어의 이 구석에서 표준에 가장 가까운 것이다. 요약이 아니라 원문을 읽을 가치가 있다. 이 글은 빠지는 부분들에 관한 것이다.&lt;/p&gt;
&lt;h2&gt;Keep a Changelog는 무엇을 요구하는가&lt;/h2&gt;
&lt;p&gt;저장소 루트에 있는 &lt;code&gt;CHANGELOG.md&lt;/code&gt;, 최신순, 버전마다 섹션 하나. 각 버전은 번호와 ISO 날짜를 가지며, 그 항목들을 여섯 가지 유형 아래 묶는다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;유형&lt;/th&gt;
&lt;th&gt;용도&lt;/th&gt;
&lt;th&gt;빼먹을 때의 대가&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Added&lt;/td&gt;
&lt;td&gt;새로운 기능&lt;/td&gt;
&lt;td&gt;없음. 아무도 이것은 빼먹지 않는다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Changed&lt;/td&gt;
&lt;td&gt;기존 동작의 변경&lt;/td&gt;
&lt;td&gt;독자가 동작이 바뀐 것을 오류를 통해 알게 된다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deprecated&lt;/td&gt;
&lt;td&gt;곧 제거될 기능&lt;/td&gt;
&lt;td&gt;제거가 예정된 사건이 아니라 사고가 되어버린다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Removed&lt;/td&gt;
&lt;td&gt;이번 릴리스에서 제거된 기능&lt;/td&gt;
&lt;td&gt;제거인지 버그인지 아무도 구분할 수 없다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;버그 수정&lt;/td&gt;
&lt;td&gt;없음. 이것도 아무도 빼먹지 않는다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security&lt;/td&gt;
&lt;td&gt;취약점&lt;/td&gt;
&lt;td&gt;그것을 찾고 있던 그 한 명의 독자가 찾지 못한다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;여기에 맨 위의 &lt;code&gt;Unreleased&lt;/code&gt; 섹션이 더해진다. 그래서 항목이 병합되는 즉시 넣어둘 곳이 있고, 누구나 다음에 무엇이 올지 볼 수 있다.&lt;/p&gt;
&lt;p&gt;이것이 거의 전부다. 나머지는 근거다. 항목은 사람을 위한 것이고, 변경 사항마다 항목 하나이며, 이 파일은 로그가 아니라 문서라는 것.&lt;/p&gt;
&lt;h2&gt;Keep a Changelog의 어떤 부분이 빠지는가&lt;/h2&gt;
&lt;p&gt;Unreleased 섹션, 이어서 여섯 유형 중 네 개(Security도 그중 하나)가 순서대로 빠진다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Unreleased&lt;/code&gt;가 가장 먼저 사라진다.&lt;/strong&gt; 이것은 기한이 없는 섹션이라, 유지 관리가 가장 먼저 멈추는 섹션이며, 사라지고 나면 항목은 릴리스 시점에 커밋 히스토리로부터 쓰이게 된다. 그것이 바로 명세가 서두에서 경고하는 git log 덤프이며, 서서히 그렇게 도달하게 된다. &lt;a href=&quot;https://changeloop.dev/blog/ko/changelog-automation/&quot;&gt;체인지로그 자동화&lt;/a&gt;는 대체로 이 섹션을 누군가 기억하지 않아도 살아 있게 유지하는 것에 관한 글이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;여섯 유형이 두 개로 무너진다.&lt;/strong&gt; 실제 체인지로그 대부분은 결국 Added와 Fixed로 귀결된다. Changed와 Deprecated는 누군가 무엇에 의존하고 있었는지에 대한 판단을 요구하기 때문이다. 그 판단이야말로 가치 있는 부분이다. 특히 Deprecated는 미래에 대한 약속인 유일한 유형이며, 그것을 빼먹는 것이 제거가 사고로 변하는 방식이다. 그 약속을 지키는 메커니즘은 &lt;a href=&quot;https://changeloop.dev/blog/ko/api-deprecation/&quot;&gt;API를 비추천 처리하는 방법&lt;/a&gt;에 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Security가 더는 분리되지 않는다.&lt;/strong&gt; Fixed 아래 등록된 보안 수정은 그것을 찾고 있던 바로 그 독자에게 보이지 않는다. 수정이 사소하더라도, 특히 주목받고 싶지 않을 때일수록 분리해서 유지하라.&lt;/p&gt;
&lt;h2&gt;이 명세는 무엇에 답하지 않는가&lt;/h2&gt;
&lt;p&gt;이것은 파일 형식이다. 이것을 도입한 직후 바로 마주치게 되는 질문들에 대해서는 아무것도 말하지 않는다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;어떻게 사람들이 그것을 알게 되는가?&lt;/strong&gt; 저장소 안의 파일은 기여자에게는 닿는다. GitHub를 한 번도 열어본 적 없는 고객에게는 닿지 않는다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;버전이 없는 제품은 어떻게 하는가?&lt;/strong&gt; 지속적으로 배포되는 서비스에는 묶을 수 있는 v4.2.0이 없다. 대부분의 팀은 날짜로 대체하며, 이것은 잘 작동하고, 명세는 이를 승인하지도 금지하지도 않는다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;누가 항목을 쓰는가?&lt;/strong&gt; 명세는 사람이 쓴다고 가정한다. 언제 쓰는지는 말하지 않는다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;여러 독자층은 어떻게 하는가?&lt;/strong&gt; 파일 하나는 개발자에게 유용하다. 그것은 비기술적인 관리자에게 같은 내용을 제공하지 않으며, 그들을 위해 손으로 다시 포맷하는 것이 중복이 시작되는 지점이다. &lt;a href=&quot;https://changeloop.dev/blog/ko/changelog-vs-release-notes/&quot;&gt;체인지로그 대 릴리스 노트&lt;/a&gt;가 이 명세가 남겨둔 분리 작업이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이 발상의 더 엄격한 파생인 &lt;a href=&quot;https://common-changelog.org/&quot;&gt;Common Changelog&lt;/a&gt;는 이 중 일부를 조인다. 특정 항목 문구를 금지하고, 변경 사항으로의 링크를 요구하며, 독자가 누구인지에 대해 확고한 입장을 가진다. Keep a Changelog의 느슨한 부분들이 팀에서 계속 논쟁거리라면 읽어볼 가치가 있다.&lt;/p&gt;
&lt;h2&gt;git log를 쏟아붓지 않고 Keep a Changelog를 자동화할 수 있는가&lt;/h2&gt;
&lt;p&gt;가능하다. 구조화된 커밋으로부터 초안을 도출하고, 유형을 미리 채운 상태로 Unreleased에 넣고, 릴리스가 잘리기 전에 사람이 문구를 편집하도록 요구하라. 명세의 경고는 도구가 아니라 결과물에 관한 것이다. 커밋으로부터 초안을 도출하는 것은 괜찮다. 그 초안을 편집 없이 그대로 발행하는 것이 명세가 반대하는 대상이다.&lt;/p&gt;
&lt;p&gt;기계는 수집과 포맷팅을 담당한다. 그것은 기계가 잘하는 일이다. 사람은 선별과 문구를 담당한다. 그것은 기계가 잘하지 못하는 일이다. &lt;a href=&quot;https://changeloop.dev/blog/ko/conventional-commits-changelog/&quot;&gt;Conventional commits&lt;/a&gt;는 이것이 의존하는 두 계층 분리와, 어떤 커밋 유형이 위 여섯 범주 중 어디에 대응하는지를 다룬다. 우리의 &lt;a href=&quot;https://changeloop.dev/changelog-tools&quot;&gt;체인지로그 도구&lt;/a&gt; 정리는 수집 부분을 위해 무엇이 있는지 다룬다.&lt;/p&gt;
&lt;h2&gt;Keep a Changelog는 어디서 충분하지 않게 되는가&lt;/h2&gt;
&lt;p&gt;배포에서 멈춘다. Keep a Changelog는 &amp;quot;이 파일이 어떤 모습이어야 하는가&amp;quot;에 대한 좋은 답이다. &amp;quot;우리 사용자들이 무엇이 바뀌었는지 어떻게 알게 되는가&amp;quot;에 대한 답은 아니다. 저장소 안의 Markdown 파일은 여러분의 사용자가 기여자일 때만 작동하는 배포 전략이기 때문이다.&lt;/p&gt;
&lt;p&gt;그것이 대부분의 팀이 두 번째로 마주치는 간극이다. 파일 자체는 괜찮은데, 팀 밖의 아무도 그것을 읽지 않는다. 이것을 해결한다는 것은 항목들이 다른 어딘가에서 렌더링될 수 있는 데이터가 되어야 한다는 뜻이며, 이것은 파일을 포맷하는 것과는 다른 문제다. 그것이 &lt;a href=&quot;https://changeloop.dev/changelog-examples&quot;&gt;체인지로그 예시&lt;/a&gt;가 저장소 파일이 아니라 공개된 체인지로그 페이지들을 모아 놓은 이유다. 그 항목들을 사람들이 다시 찾아오는 것으로 바꾸는 방법은
&lt;a href=&quot;https://changeloop.dev/blog/ko/changelog-page/&quot;&gt;체인지로그 페이지 만드는 법&lt;/a&gt;에서 다룬다.&lt;/p&gt;
&lt;p&gt;그럼에도 이 명세를 도입하라. 반나절이면 되고, 두 번째 문제를 다룰 수 있게 만들어주며, 여전히 이 주제에 관해 쓰인 최고의 한 페이지다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Keep a Changelog는 표준인가?&lt;/strong&gt;
널리 채택된 관례이지, 표준화 기구의 사양이 아니다. 도구들(릴리스 스크립트, 린터, 파서)이 그 형태를 충분히 자주 가정하기 때문에, 이를 따르는 것이 호환성을 사준다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Unreleased 섹션에는 무엇이 들어가는가?&lt;/strong&gt;
병합되었지만 번호가 매겨진 릴리스로는 아직 출시되지 않은 변경 사항마다의 항목. 릴리스가 잘리면 그 섹션은 버전과 날짜로 이름이 바뀌고, 그 위에 새로운 빈 Unreleased 섹션이 놓인다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;체인지로그는 시맨틱 버저닝을 사용해야 하는가?&lt;/strong&gt;
Keep a Changelog는 이를 권장하지만 요구하지는 않는다. 라이브러리와 API는 이로부터 이득을 얻는다. 지속적으로 배포되는 서비스는 보통 날짜로 대체하며, 이 형식은 그것을 수용한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;보안 수정 사항은 공개되기 전에 체인지로그에 있어야 하는가?&lt;/strong&gt;
수정이 출시될 때 항목을 추가하되, 운영자가 조치를 취할 수 있을 만큼의 세부 사항만 담아라. 공동 공개 날짜까지 항목을 미루는 것은 정상이지만, 아예 빠뜨리는 것은 그렇지 않다.&lt;/p&gt;
</content:encoded></item><item><title>지킬 가치가 있는 릴리스 노트 모범 사례</title><link>https://changeloop.dev/blog/ko/release-notes-best-practices/</link><guid isPermaLink="true">https://changeloop.dev/blog/ko/release-notes-best-practices/</guid><description>릴리스 노트 모범 사례 목록의 대부분은 문체 조언에 지나지 않는다. 독자의 행동을 실제로 바꾸는 사례와 유행만 좇는 흔한 세 가지 사례를 살펴본다.</description><pubDate>Fri, 28 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;정말로 중요한 릴리스 노트 모범 사례는 결과가 뒤따르는 것들이다. 병합 시점에 항목을 쓰고, 누가 영향을 받는지 이름을 밝히고, 필요한 조치가 없더라도 그것을 명시하고, 파괴적 변경에는 날짜를 붙이고, 변경 사항마다 영구적인 항목 하나를 유지하고, 결과별로 묶고, 지루한 섹션을 남겨두는 것. 이들 각각은 독자의 실제 행동을 바꾼다. 이 주제에 관한 나머지 조언들은 대부분 노트가 보이는 모습만 바꿀 뿐이다.&lt;/p&gt;
&lt;p&gt;릴리스 노트 모범 사례를 검색하면 문체에 대한 조언이 나온다. 명확하게 쓰라, 간결하게 쓰라, 쉬운 언어를 쓰라, 스크린샷을 추가하라. 어느 것도 틀리지 않았지만 어느 것도 아무것도 바꾸지 않는다. 일부러 불명확하게 쓰려고 자리에 앉은 팀은 없기 때문이다. 아래의 관행들에는 각각 건너뛸 때 치러야 할 대가가 따라온다. 실패 사례가 붙어 있지 않은 관행은 그저 취향일 뿐이기 때문이다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;관행&lt;/th&gt;
&lt;th&gt;건너뛸 때의 대가&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;릴리스 시점이 아니라 병합 시점에 항목을 쓴다&lt;/td&gt;
&lt;td&gt;나중에 재구성된 항목은 &amp;quot;여러 가지 개선 사항&amp;quot;이라고만 말하게 된다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;누가 영향을 받는지 이름을 밝힌다&lt;/td&gt;
&lt;td&gt;모든 독자가 자신에게는 해당되지 않는다고 판단해버린다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;필요한 조치를 &amp;quot;없음&amp;quot;까지 포함해 명시한다&lt;/td&gt;
&lt;td&gt;똑같은 지원 티켓이 마흔 건 쌓이고, 독자들은 최악을 가정한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;파괴적 변경에는 버전이 아니라 날짜를 붙인다&lt;/td&gt;
&lt;td&gt;기한이 지나고 나서야 그것이 있었다는 사실을 알게 된다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;변경 사항마다 링크 가능한 영구 항목 하나를 유지한다&lt;/td&gt;
&lt;td&gt;&amp;quot;이게 언제 바뀌었지&amp;quot;에 아무도 답할 수 없다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;시스템이 아니라 결과별로 묶는다&lt;/td&gt;
&lt;td&gt;독자가 자신의 섹션을 찾으려면 여러분의 아키텍처를 알아야 한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;지루한 섹션을 유지한다&lt;/td&gt;
&lt;td&gt;보안팀, 컴플라이언스 담당자, 버전 불일치를 디버깅하는 사람이 유일한 출처를 잃는다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;릴리스 노트의 모범 사례는 무엇인가&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;릴리스 시점이 아니라 병합 시점에 항목을 써라.&lt;/strong&gt;
건너뛸 때의 대가: 커밋 히스토리로부터 릴리스를 재구성하는 사람은 실제로 변경을 만든 사람이 아니며, 의도를 추측하게 된다. 몇 주 후에 쓰인 항목이 &amp;quot;여러 가지 개선 사항&amp;quot;이라고만 말하는 항목이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;누가 영향을 받는지 이름으로 밝혀라.&lt;/strong&gt;
&amp;quot;Business 요금제 사용 팀&amp;quot;, &amp;quot;v1 내보내기 API를 사용하는 모든 사람&amp;quot;, &amp;quot;Postgres 14에서 셀프 호스팅하는 설치본&amp;quot;. 건너뛸 때의 대가: 모든 독자가 자신에게 해당되는지 직접 판단해야 하고, 대부분은 아니라고 결정해버린다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;필요한 조치를, 없을 때조차, 명시하라.&lt;/strong&gt;
건너뛸 때의 대가: 지원팀이 똑같은 질문에 마흔 번 답하게 되고, 묻지 않은 독자들은 그냥 무언가 필요하다고 짐작하고 미뤄버린다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;파괴적 변경에는 릴리스 번호가 아니라 날짜를 붙여라.&lt;/strong&gt;
&amp;quot;v5에서 제거됨&amp;quot;은 v5가 언제 나올지 모르는 사람에게는 아무 의미가 없다. &amp;quot;11월 1일부터 작동하지 않습니다&amp;quot;는 달력에 적어둘 수 있는 날짜다. 건너뛸 때의 대가: 기한이 지나고 나서야 그것을 알게 된다. 무엇이 파괴적 변경으로 취급되는지, 그리고 그것을 출시하기 위한 체크리스트는 &lt;a href=&quot;https://changeloop.dev/blog/ko/breaking-changes/&quot;&gt;파괴적 변경이란 무엇인가&lt;/a&gt;에 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;변경 사항마다 링크 가능한 영구 항목 하나를 유지하라.&lt;/strong&gt;
이메일은 보관소가 아니고 Slack 메시지는 참고 자료가 아니다. 건너뛸 때의 대가: 여섯 달 뒤에는 여러분 자신을 포함해서 &amp;quot;이게 언제 바뀌었지&amp;quot;에 아무도 답할 수 없다. 이메일에도 여전히 역할이 있으며, &lt;a href=&quot;https://changeloop.dev/blog/ko/product-update-email/&quot;&gt;제품 업데이트 이메일 템플릿&lt;/a&gt;에서 다룬다. 항목을 대체하는 대신 그것을 가리킨다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;시스템이 아니라 결과별로 묶어라.&lt;/strong&gt;
건너뛸 때의 대가: 독자가 어떤 섹션이 자신에게 중요한지 알아내려면 여러분의 아키텍처를 머릿속에 담고 있어야 한다. 여기서 따라 나오는 순서 배치 방식은 &lt;a href=&quot;https://changeloop.dev/blog/ko/how-to-write-release-notes/&quot;&gt;릴리스 노트를 쓰는 방법&lt;/a&gt;에 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;지루한 섹션을 유지하라.&lt;/strong&gt;
의존성 업데이트와 내부 변경 사항은 맨 아래에 한 줄씩 남겨둔다. 건너뛸 때의 대가: 보안팀, 컴플라이언스 검토자, 버전 불일치를 디버깅하는 사람 모두가 유일한 출처를 잃는다. 이 부분을 가장 자주 틀리는 항목은 수정 사항이며, &lt;a href=&quot;https://changeloop.dev/blog/ko/bug-fix-release-notes/&quot;&gt;버그 수정 릴리스 노트&lt;/a&gt;는 독자가 조치해야 하는지 알 수 있도록 그것을 쓰는 방법을 보여준다.&lt;/p&gt;
&lt;h2&gt;체인지로그 모범 사례는 무엇이고, 무엇이 다른가&lt;/h2&gt;
&lt;p&gt;체인지로그는 참고 자료이므로, 그 관행들은 설득이 아니라 완전성과 구조에 관한 것이다. 중요한 네 가지는 다음과 같다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;줄마다 고정된 항목 유형.&lt;/strong&gt; Added, Changed, Deprecated, Removed, Fixed, Security. 이것은 하우스 스타일이 아니라 필터다. 누군가 &amp;quot;파괴적 변경만&amp;quot; 요청할 수 있게 해주는 것이다. &lt;a href=&quot;https://changeloop.dev/blog/ko/keep-a-changelog-implemented/&quot;&gt;Keep a Changelog&lt;/a&gt; 관례가 보통의 출처다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;미출시 섹션.&lt;/strong&gt; 병합과 릴리스 사이에 항목들이 머무는 곳. 이것이 없으면 팀은 항목을 늦게 쓰게 된다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ISO 날짜.&lt;/strong&gt; &lt;code&gt;2026-08-28&lt;/code&gt;이지, &lt;code&gt;28/08/26&lt;/code&gt;이 아니다. 후자는 독자에 따라 서로 다른 날을 의미한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;커밋이 아니라 변경 사항마다 항목 하나.&lt;/strong&gt; 하나의 버그를 고친 세 개의 커밋은 하나의 항목이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이 두 성과물은 &lt;a href=&quot;https://changeloop.dev/blog/ko/changelog-vs-release-notes/&quot;&gt;체인지로그 대 릴리스 노트&lt;/a&gt;에서 제대로 비교된다. 짧게 말하면, 체인지로그의 관행은 완전성을 지키고 릴리스 노트의 관행은 주의를 지킨다.
&lt;a href=&quot;https://changeloop.dev/blog/ko/private-release-notes-enterprise/&quot;&gt;엔터프라이즈 고객을 위한 비공개 릴리스 노트&lt;/a&gt;는
고객이 더 이상 모두 같은 빌드에 있지 않게 되었을 때만 나타나는 이것의 버전을 다룬다. 같은
완전성과 주의라는 목표지만, 모두에게 한꺼번에 방송하는 대신 계정별로 조정된다.&lt;/p&gt;
&lt;h2&gt;유행만 좇는 세 가지&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;항목 유형으로서의 이모지.&lt;/strong&gt; 로켓과 렌치는 분류 체계가 아니다. 깔끔해 보이지만 필터링도, 정렬도, 스크린 리더로 유의미하게 읽히지도 않는다. 단어를 쓰고, 이모지를 원한다면 단어 뒤에 붙여라.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;호스팅 제품의 헤드라인으로 쓰이는 시맨틱 버전 번호.&lt;/strong&gt; 시맨틱 버저닝은 API 호환성에 대한 약속이다. 아무도 자신의 버전을 선택하지 않는 SaaS 제품에서 헤드라인에 들어간 버전 번호는 뉴스로 치장한 내부 정리용 라벨일 뿐이다. 시맨틱 버전은 체인지로그 안에 두고 발표 문구에서는 빼라.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;내용과 무관하게 일정에 맞춰 발행하기.&lt;/strong&gt; 아무 내용도 없는 월간 노트는 사람들에게 여러분의 노트가 소음이라고 가르친다. 할 말이 있을 때 발행하라. 나머지는 체인지로그가 담당한다.&lt;/p&gt;
&lt;h2&gt;실제로 어려운 것 하나&lt;/h2&gt;
&lt;p&gt;체인지로그와 발표 문구를 두 번 쓰지 않으면서 서로 맞춰 유지하는 일이다.&lt;/p&gt;
&lt;p&gt;대부분의 팀은 하나의 페이지로 시작해서, 독자층이 갈라지면 나누고, 그러고 나서 둘 중 하나를 조용히 썩게 내버려둔다. 보통은 체인지로그다. 그것에는 기한이 붙어 있지 않기 때문이다. 벗어나는 방법은 규율이 아니라 구조에 있다. 항목을 유형, 날짜, 대상 독자를 가진 데이터로 유지하고, 두 표면 모두를 그 데이터의 렌더링으로 다루는 것이다. 우리의 &lt;a href=&quot;https://changeloop.dev/changelog-tools&quot;&gt;체인지로그 도구&lt;/a&gt; 정리는 우리가 경쟁하는 도구를 포함해 그것을 위해 무엇이 존재하는지를 다루며, &lt;a href=&quot;https://changeloop.dev/beamer-alternative&quot;&gt;Beamer 대안&lt;/a&gt; 페이지는 대부분의 팀이 출발점으로 삼는 위젯과의 정직한 비교다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://changeloop.dev/release-notes-template&quot;&gt;릴리스 노트 템플릿&lt;/a&gt;은 항목들이 이미 존재할 때 선별 단계가 이루어지는 곳이다.&lt;/p&gt;
&lt;h2&gt;하나만 채택한다면&lt;/h2&gt;
&lt;p&gt;병합 시점에, 고정된 형식으로, 유형을 붙여서 항목을 써라. 이 페이지의 다른 모든 관행은 이것이 자리 잡고 나면 더 쉬워지고, 그것 없이는 어느 것도 살아남지 못한다.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;릴리스 노트에는 스크린샷이 있어야 하는가?&lt;/strong&gt;
실제로 바뀐 것이 사용되는 모습만 넣어라. 아무도 방문한 적 없는 설정 페이지의 스크린샷은 정보가 아니라 스크롤만 늘린다. 결과와 영향받는 독자를 이름으로 밝힌 텍스트가, 둘 다 보여주지 않는 이미지보다 낫다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;파괴적 변경에 대한 릴리스 노트는 어떻게 쓰는가?&lt;/strong&gt;
날짜를 먼저, 영향받는 호출자를 두 번째로, 필요한 조치를 세 번째로, 이전 방법을 네 번째로 둔다. 버전 번호로 시작하지 마라. 예시 항목과 함께 전체 형식은 &lt;a href=&quot;https://changeloop.dev/blog/ko/breaking-changes/&quot;&gt;파괴적 변경이란 무엇인가&lt;/a&gt;에 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;릴리스 노트는 엔지니어링이 써야 하는가, 마케팅이 써야 하는가?&lt;/strong&gt;
변경을 만든 엔지니어가 병합 시점에 초안을 쓰고, 그것을 낯선 사람처럼 읽는 누군가가 편집해야 한다. 둘 중 하나만으로는 고객이 실행에 옮길 수 있는 노트가 나오지 않는다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;이상적인 릴리스 노트 형식은 무엇인가?&lt;/strong&gt;
기한이 있는 항목을 먼저, 다음으로 새로운 기능, 다음으로 개선 사항, 그리고 나머지는 한 줄씩 목록으로. &lt;a href=&quot;https://changeloop.dev/release-notes-template&quot;&gt;릴리스 노트 템플릿&lt;/a&gt;이 그 형식을 채워 넣는 페이지로 만든 것이다.&lt;/p&gt;
</content:encoded></item></channel></rss>