브레이킹 체인지
Breaking Change
개념
이미 연동해 쓰던 쪽의 코드를 멈춰 세우는 규격 변경으로, 판을 나누거나 미리 알려 피해를 줄입니다.
등장 배경
혼자 쓰는 코드에서 이름을 바꾸는 일은 아무 일도 아닙니다. 고칠 자리가 전부 한 저장소 안에 있으니 찾아서 같이 고치면 됩니다.
API를 열어 남이 붙기 시작하면 사정이 달라집니다. API는 프로그램끼리 무엇을 어떻게 주고받을지 정해 둔 창구인데, 그 창구를 쓰는 코드는 우리 저장소에 없습니다. 태오가 응답에서 아무도 안 쓸 것 같은 칸 하나를 지우고 배포했습니다. 테스트는 전부 통과했고 서비스도 멀쩡했습니다. 다음 날 아침 연동사 세 곳에서 결제 화면이 멈췄다는 문의가 들어왔습니다. 세 곳 모두 그 칸을 읽고 있었습니다.
곤란한 부분은 누구도 실수하지 않았다는 데 있습니다. 태오는 쓰이지 않는 칸이라고 판단했고, 연동사는 문서에 적힌 대로 읽었을 뿐입니다. 어긋난 것은 혼자 고칠 수 있다고 여긴 것이 사실은 양쪽의 약속이었다는 점입니다.
그래서 변경을 두 종류로 갈라 부르기 시작했습니다. 우리 쪽에서만 끝나는 변경과 쓰던 쪽 코드를 멈춰 세우는 변경입니다. 뒤쪽에 이름이 붙으면 배포 전에 한 문장으로 확인할 수 있습니다.
작동 방식
쓰는 쪽이 이미 기대하고 있던 모양을 없애거나 바꾸면 깨지고, 없던 것을 더하기만 하면 깨지지 않습니다. 판별은 이 한 줄에서 나옵니다. 깨뜨리는 변경은 대개 넷 중 하나입니다.
- 응답에서 칸을 없애거나 이름을 바꿉니다.
email을email_address로 바꾸면 쓰던 쪽은 없는 칸을 읽고 빈 값을 화면에 그립니다. - 필수 입력을 새로 요구합니다. 어제까지 통하던 요청이 오늘은 거절당하고, 상태 코드 400 처럼 잘못된 요청이라는 숫자가 돌아옵니다.
- 값의 형식이나 뜻을 바꿉니다. 시각을 밀리초에서 초 단위로 바꾸거나 날짜 표기를 다른 형식으로 바꾸는 경우입니다.
- 주소나 기본 동작을 바꿉니다. 목록을 한 번에 100건씩 주던 창구가 20건씩 주기 시작하면, 한 번만 부르고 끝내던 쪽은 나머지 80건을 잃은 채로 돌아갑니다.
셋째가 가장 다루기 어렵습니다. 앞의 둘은 에러가 나서 금방 드러나지만 형식만 바뀐 응답은 문제없이 처리됩니다. 어제 올린 문서의 작성 시각이 1970년으로 찍히는데 로그에는 성공만 쌓입니다. 며칠 뒤 정렬이 이상하다는 문의로 발견됩니다.
반대쪽은 하위 호환성이라고 부릅니다. 새 칸을 더하고, 선택 입력을 늘리고, 새 주소를 여는 변경은 옛 방식으로 부르던 쪽을 건드리지 않습니다. 칸을 없애는 대신 새 칸을 더하고 옛 칸은 한동안 같이 내보내는 식으로 갑니다.
다만 더하기가 언제나 안전하지는 않습니다. 받는 쪽이 모르는 칸이 하나라도 오면 오류를 내도록 짜여 있으면 추가도 사고가 됩니다. 그래서 JSON처럼 사람이 읽을 수 있는 형식으로 주고받는 창구는 모르는 칸은 무시한다는 규칙을 문서에 먼저 적어 둡니다.
쓰이는 곳
남이 의존하는 규격이 있는 곳이면 어디서나 같은 문제가 생깁니다. 자주 나오는 자리는 셋입니다.
- 밖에 열어 둔 API. REST처럼 주소로 자원을 다루는 창구를 공개해 두었다면 누가 쓰는지 다 알 수 없으므로, 깨는 대신 API 버저닝으로 옛 판과 새 판을 나란히 둡니다.
- 라이브러리와 SDK. 여기서는 시맨틱 버저닝의 첫 자리가 신호입니다. 2.4.1 에서 3.0.0 으로 올라간 것은 깨는 변경이 들었다는 뜻이고, 쓰는 쪽은 그 자리만 보고 업데이트를 멈춥니다.
- 회사 안의 서비스끼리. 데이터베이스의 칸 이름이나 서비스 사이에 오가는 이벤트의 모양도 같은 성격이라, 두 서비스가 다른 일정으로 배포되는 순간 밖에 연 API 와 다를 바 없습니다.
깨야만 하는 변경이 생기면 순서를 밟습니다.
- 디프리케이션 공지를 먼저 냅니다. 곧 없앨 예정임을 알리고 무엇으로 옮기면 되는지를 같이 적습니다.
- 유예 기간을 둡니다. 여섯 달에서 열두 달이 흔하고, 그동안 옛 방식도 계속 받아 줍니다.
- 누가 아직 쓰는지 셉니다. 호출 기록에 남은 곳이 몇인지 나오고, 소수만 남았으면 직접 연락합니다.
- 정해 둔 날짜에 제거합니다.
규격을 OpenAPI처럼 기계가 읽는 형식으로 적어 두면 판단을 도구가 대신합니다. 지난 판과 새 판을 비교해 사라진 칸과 새로 생긴 필수 입력을 짚어 주므로, 눈으로 훑다 놓치는 자리가 줄어듭니다.
실무 용례
"이건 브레이킹 체인지예요. 칸 이름만 바꾸는 게 아니라 쓰던 쪽 코드가 멈춥니다."
작아 보이는 수정이 사실은 바깥 서비스를 멈추는 변경이라고 짚는 말입니다.
"메이저 버전을 올려야 합니다. 마이너로 나가면 자동으로 올라간 쪽이 깨져요."
버전 번호의 어느 자리를 올릴지가 곧 경고를 보낼지 말지의 결정이라는 뜻입니다.
"여섯 달 유예 두고 디프리케이션 공지부터 내보내죠."
지금 당장 없애지 말고 옮겨 갈 시간을 준 뒤에 제거하자는 제안입니다.
페이지덱에서는 태오가 배포 전 검토에서 이 질문을 먼저 던집니다. 지난번 사고 뒤로는 응답에서 무언가를 빼는 변경에 한 사람의 승인이 더 붙게 됐습니다. 지현은 외부 연동이 걸린 변경이면 일정을 다시 잡습니다. 유예 기간이 필요한 변경은 이번 주에 끝나지 않고 반년짜리 일이 되기 때문입니다.
수아 쪽에서 먼저 소식이 오기도 합니다. 연동한 고객사가 자기네 배포 일정을 알려 오면 그에 맞춰 제거 날짜를 미룹니다.
흔한 오해
테스트가 전부 통과했으니 안전하다고 읽는 경우가 가장 많습니다. 배포 전에 도는 검사가 초록색이면 문제가 없다는 뜻으로 배웠으니 자연스러운 판단입니다. 하지만 깨지는 코드는 우리 저장소에 없습니다. 우리 테스트는 우리가 부르는 방식만 확인하고, 연동사가 어떤 칸을 읽는지는 아무도 검사하지 않습니다. 그대로 두면 사고는 늘 배포 다음 날 아침 남의 문의로 발견됩니다.
공지를 냈으니 브레이킹 체인지가 아니라고 보는 것도 흔합니다. 미리 알리면 책임을 다했다고 느끼기 때문입니다. 공지가 바꾸는 것은 성격이 아니라 시간입니다. 변경은 그대로 남의 코드를 멈추고, 공지는 옮길 기회를 줄 뿐입니다. 이 둘을 섞으면 하루 전 공지도 괜찮다는 결론이 나오고, 유예 기간이라는 개념이 사라집니다.
자주 헷갈리는 용어
같이 보면 좋은 페이지
마지막 업데이트 2026-09-16