두 JSON 파일을 비교하고 변경 사항을 찾는 방법
두 JSON 파일을 비교하는 가장 빠른 방법은 두 파일을 나란히 보여주는 diff 도구에 붙여넣고, 같은 방식으로 포맷한 다음, 도구가 강조 표시한 줄을 읽는 것입니다. 어려운 부분은 대개 비교 자체가 아니라 노이즈 처리입니다. 키 순서 변경, 들여쓰기 차이, 불필요한 후행 쉼표로 인해 거의 동일한 파일이 공통점이 전혀 없는 것처럼 보일 수 있습니다.
이 가이드는 깔끔하고 신뢰할 수 있는 diff를 얻는 방법을 안내합니다. JSON 파일이 의미적으로 동일하더라도 텍스트상으로 차이가 나는 이유, 알아두어야 할 몇 가지 방법, 그리고 직접 따라해볼 수 있는 실제 예시를 살펴봅니다. 도구만 필요하다면 JSON 비교 페이지에서 브라우저에서 바로 처리할 수 있습니다.
JSON 파일 비교가 생각보다 어려운 이유
JSON은 작고 엄격한 문법을 가지고 있지만(사양은 json.org 참조), 텍스트 레이아웃 방식에 대한 자유도가 높습니다. 두 파일이 완전히 동일한 객체를 나타내더라도 바이트 단위로는 다를 수 있습니다. 일반 텍스트 diff는 그런 사실을 알지 못하므로 모든 차이를 충실히 표시합니다.
비교를 시작하기 전에 반드시 이해해야 할 점이 있습니다. JSON 객체의 키에는 순서가 없습니다.
사양(RFC 8259)은
객체를 이름/값 쌍의 순서 없는 집합으로 정의합니다. 따라서
{"name":"Ada","id":7}와 {"id":7,"name":"Ada"}는
동일하지만, 행 기반 diff에서는 빨간색과 녹색으로 표시됩니다.
| diff에서 보이는 것 | 실제 변경인가? | 해결 방법 |
|---|---|---|
| 다른 순서의 키 | 아니요, 객체는 순서 없음 | 양쪽 키를 정렬 |
| 2칸 vs 4칸 들여쓰기 | 아니요 | 양쪽을 동일하게 포맷 |
| 압축 버전 vs 보기 좋게 출력된 버전 | 아니요 | 양쪽을 포맷 |
| 파일 끝의 후행 줄바꿈 | 아니요 | 무시하거나 공백 제거 |
값이 "7"에서 7로 변경 | 예, 문자열 vs 숫자 | 조사 필요, 실제 변경 |
| 다른 순서의 배열 항목 | 경우에 따라, 배열은 순서 있음 | 여기서 순서가 중요한지 판단 |
마지막 행에서 자주 실수합니다. 배열은 순서를 유지하지만 객체는 유지하지 않습니다.
따라서 [1, 2, 3]과 [3, 2, 1]은 실제로 다르지만,
객체 내의 키는 자유롭게 순서가 바뀔 수 있습니다. JavaScript가 이를 어떻게 파싱하는지
자세히 알고 싶다면 MDN에 훌륭한
JSON 객체 참조가 있습니다.
JSON을 비교하는 4가지 방법과 각각의 활용 시기
단일한 최선의 방법은 없습니다. 파일이 어디에 있고 무엇을 알아내려는지에 따라 다릅니다. 일반적인 옵션들을 비교해봅니다.
| 방법 | 적합한 경우 | 노력 | JSON 이해 여부 |
|---|---|---|---|
| 눈으로 확인 | 작은 파일, 하나 또는 두 개의 필드 | 낮음 | 아니요, 직접 파싱 |
| 온라인 diff 도구 | 빠른 확인, 어디서든 붙여넣기 | 낮음 | 포맷 + 키 정렬로 가능 |
커맨드 라인 (jq, diff) | 디스크의 파일, 스크립팅, 큰 파일 | 중간 | 먼저 정렬하면 가능 |
IDE 또는 git diff | 저장소에 있는 파일 | 커밋된 경우 낮음 | 기본적으로 행 기반 |
대부분의 사람에게 브라우저 도구는 설치할 것이 없고 로그나 API 호출에서 바로 스니펫을 붙여넣을 수 있어 속도 면에서 유리합니다. 문제는 포맷 노이즈인데, 다음에서 해결합니다. 터미널에서 주로 작업한다면 jq를 배우는 것이 좋으며, 중요한 플래그 하나를 소개합니다.
가장 빠른 깔끔한 비교, 단계별로
누군가 두 개의 설정 파일을 건네며 "뭐가 다른가요?"라고 물을 때 사용하는 루틴입니다. 약 15초가 걸립니다.
- JSON 비교 도구를 엽니다.
- 왼쪽에 원본을, 오른쪽에 새 버전을 붙여넣습니다.
- 양쪽에서 포맷을 클릭하여 동일한 들여쓰기를 사용하도록 합니다.
- 키 정렬(정규화)을 켜서 키 순서 변경이 변경 사항으로 표시되지 않도록 합니다.
- 결과를 읽습니다. 녹색은 추가, 빨간색은 삭제, 변경된 값은 각각 하나씩 표시됩니다.
3단계와 4단계가 핵심입니다. 두 파일이 동일하게 포맷되고 키가 정렬되면, 강조 표시되는 것은 실제로 변경된 내용뿐입니다. diff 엔진은 Google의 diff-match-patch를 기반으로 하며, 먼저 행 단위로 비교하므로 긴 파일에서도 빠르게 동작합니다.
실제 예시
사용자 레코드 변경 사항을 검토하고 있다고 가정합니다. 변경 전:
{
"name": "Ada Lovelace",
"role": "editor",
"active": true,
"seats": 3
}
그리고 팀원이 전달한 변경 후:
{
"active": true,
"name": "Ada Lovelace",
"role": "admin",
"seats": 5,
"team": "platform"
}
이를 원시 행 diff에 넣으면 키 순서가 달라서 거의 모든 줄이 이동한 것처럼 보입니다. 양쪽을 포맷하고 정렬하면 실제 내용은 간단합니다:
| 필드 | 변경 전 | 변경 후 | 변경 사항 |
|---|---|---|---|
role | editor | admin | 수정 |
seats | 3 | 5 | 수정 |
team | — | platform | 추가 |
name | Ada Lovelace | Ada Lovelace | 변경 없음 |
active | true | true | 변경 없음(이동만) |
실제 변경은 세 가지: 역할 변경, 좌석 수, 새 팀 필드. 순서 변경은 노이즈였습니다.
editor에서 admin으로의 승격은 리뷰에서 반드시 잡아야 할 변경 사항이지만,
20줄의 오탐지에 묻혀 있으면 놓치기 쉽습니다.
커맨드 라인에서 포맷 노이즈 제거하기
파일이 이미 디스크에 있다면, 동일한 "포맷 및 정렬" 아이디어를 두 개의 짧은 명령어로
구현할 수 있습니다. -S 플래그는 jq에게 객체 키를 정렬하도록 지시하며,
파이프로 통과시키면 두 파일이 정규화되어 일반 diff가 정확해집니다:
jq -S . old.json > old.sorted.json
jq -S . new.json > new.sorted.json
diff old.sorted.json new.sorted.json
이제 diff는 실제로 변경된 값만 보고합니다. 두 파일이 동일한 들여쓰기와
동일한 키 순서를 가지기 때문입니다. 이것은 브라우저에서 포맷 및 키 정렬을 클릭하는
것과 동일한 터미널 버전입니다.
텍스트 diff vs 구조적 diff
위의 모든 것은 텍스트 diff입니다. 빠르고 시각적이며 변경 사항을 읽는 사람에게
적합합니다. 구조적 diff는 한 단계 더 나아가 변경 사항을 데이터로 설명합니다.
이에 대한 표준은 JSON Patch로,
RFC 6902에
정의되어 있으며, 특정 경로에서 replace나 add와 같은 작업으로
편집을 표현합니다. 프로그램이 변경 사항을 적용해야 할 때(사람이 눈으로 확인하는 것이 아닐 때)
구조적 diff가 필요합니다. 일상적인 리뷰에서는 키가 정렬된 텍스트 diff로 충분합니다.
주의해야 할 일반적인 함정
| 함정 | 문제가 되는 이유 | 해결 방법 |
|---|---|---|
| 숫자 정밀도 | 2^53 − 1을 초과하는 정수는 JavaScript에서 정밀도가 손실됨 | 큰 ID는 문자열로 비교. MAX_SAFE_INTEGER 참조 |
| Unicode 이스케이프 | "café"와 "café"는 같은 문자열이지만 다른 바이트 | 양쪽을 포맷하면 인코딩이 정규화됨 |
| 중복 키 | 대부분의 파서는 마지막 키를 조용히 유지 | diff를 신뢰하기 전에 JSON을 검증 |
| 후행 쉼표 | 유효한 JSON이 아님. 파일 하나가 파싱조차 안 될 수 있음 | 먼저 문법을 수정. 유효성 검사기가 표시함 |
| 문자열 vs 숫자 | "5"와 5는 비슷해 보이지만 다른 타입 | 이것은 실제 변경 사항. 무시하지 말 것 |
관련 도구
JSON만 다루는 경우는 거의 없습니다. 환경 간 설정을 비교하려면 YAML 비교가 동일한 아이디어를 YAML에 적용합니다. 두 API 호출 간의 변경 사항을 검토하는 데는 API 응답 diff가 최적이며, 의존성 변경은 package.json diff 페이지에서 가장 읽기 쉽습니다.
자주 묻는 질문
- JSON 파일을 온라인으로 비교하면 어딘가에 업로드되나요?
- comparetext.org에서 diff는 브라우저에서 실행됩니다. 두 JSON 파일은 사용자 자신의 기기에 있는 JavaScript에 의해 비교되므로, 명시적으로 저장이나 공유를 클릭하지 않는 한 서버로 전송되는 것은 없습니다. 따라서 설정 파일, API 응답, 키를 누를 때마다 업로드하는 임의의 웹사이트에 붙여넣고 싶지 않은 데이터에도 안전합니다.
- 두 JSON 파일에서 모든 줄이 다르게 표시되는 이유는 무엇인가요?
- 거의 항상 포맷 문제이지 실제 변경이 아닙니다. 한 파일은 압축되어 있거나 탭으로 들여쓰여 있고, 다른 파일은 두 칸 들여쓰기를 사용하거나 객체 키 순서가 다릅니다. 양쪽에서 포맷을 클릭하여 동일한 들여쓰기를 사용하도록 한 다음, 키를 정렬하여 순서가 문제가 되지 않도록 합니다. 그 후 diff는 일반적으로 실제로 변경된 소수의 값으로 줄어듭니다.
- 키 순서를 무시하고 JSON을 비교하려면 어떻게 해야 하나요?
- JSON 객체 키에는 정의된 순서가 없으므로,
{"a":1,"b":2}와{"b":2,"a":1}는 동일합니다. 텍스트 diff가 이에 동의하게 하려면 비교 전에 양쪽의 키를 정렬합니다. 브라우저에서는 정규화(키 정렬)옵션을 사용합니다. 커맨드 라인에서는 jq로 할 수 있습니다:jq -S . file.json. 두 파일의 키가 동일한 정렬 순서가 되면 실제 값 변경 사항만 표시됩니다. - 페이지가 멈추지 않고 큰 JSON 파일을 비교할 수 있나요?
- 네, 어느 정도까지는 가능합니다. 행 모드 diff는 모든 문자 대신 먼저 전체 행을 비교하므로 수천 줄의 파일에서도 빠르게 유지됩니다. 매우 큰 파일(수 메가바이트)은 데이터를 스트리밍하는 jq나 git diff와 같은 커맨드 라인 도구로 처리하는 것이 좋습니다. 브라우저에서 편안하게 스크롤할 수 있는 모든 것은 온라인 diff가 더 빠른 선택입니다.
- JSON의 텍스트 diff와 구조적 diff의 차이는 무엇인가요?
- 텍스트 diff는 파일을 행 단위로 비교합니다. 두 개의 에세이를 비교하는 것과 같은 방식입니다. 구조적 diff는 JSON을 이해하므로, 키 순서 변경이 변경 사항이 아니며 배열 내에서 이동한 값이 삭제와 추가가 아닌 이동임을 알고 있습니다. 텍스트 diff는 더 빠르고 대부분의 리뷰에 충분합니다. 구조적 diff(예: RFC 6902에 따른 JSON Patch)는 프로그램이 적용할 수 있는 데이터로 변경 사항을 설명해야 할 때 중요합니다.
- 두 개의 API 응답을 비교하려면 어떻게 해야 하나요?
- 각 응답을 파일에 저장하거나 브라우저 네트워크 탭에서 복사한 다음, 왼쪽에 이전 응답, 오른쪽에 새 응답을 붙여넣습니다. 들여쓰기가 일치하도록 양쪽을 포맷하고, API가 안정적인 순서로 키를 반환하지 않으면 키를 정렬합니다. api-response-diff 도구는 바로 이를 위해 최적화되어 있습니다. 두 호출 간에 이름이 변경된 필드, 변경된 상태 코드, 문자열에서 숫자로 변경된 값을 발견하는 데 유용합니다.
직접 시도해보세요. JSON 비교 도구에 파일을 붙여넣고 무엇이 변경되었는지 확인하세요.