JSON vs YAML: 언제 무엇을 쓸지, 그리고 각각의 함정
JSON과 YAML은 같은 데이터를 모델링하지만, 실패 양상이 날카롭게 다릅니다. YAML의 타입 강제 변환과 공백 함정 대 JSON의 주석 부재와 장황함을 정리합니다.
JSON과 YAML은 같은 모양을 기술합니다. 맵, 리스트, 스칼라입니다. 그리고 둘 사이 선택은 보통 스타일 선호로 틀 지어집니다. 아닙니다. 둘은 다른 실패 양상을 가지고, 그 실패는 다른 곳에 떨어집니다. JSON의 것은 편집 시간에 물고, YAML의 것은 파스 시간에 조용히 뭅니다. 이 글은 각 형식이 어디서 값을 하는지, 나란한 메커니즘, 그리고 작동하는 설정을 새벽 2시 사고로 바꾸는 함정을 다룹니다.
관계
YAML 1.2는 실용적 목적에서 JSON의 상위 집합입니다. 모든 유효한 JSON 문서가 또한 유효한 YAML 문서인데, YAML 명세가 JSON 문법을 부분집합으로 채택했기 때문입니다. YAML 파서는 이것을 그대로 읽습니다.
{"service": "api", "replicas": 3, "ports": [80, 443]}
그것은 들리는 것보다 더 중요합니다. YAML이 JSON의 데이터 모델을 통째로 물려받는다는 뜻입니다. JSON이 표현할 수 있는데 YAML이 못 하는 것은 없습니다. 차이는 형식이 담을 수 있는 것이 아니라, 사람이 그것을 어떻게 쓰는지와, 파서가 YAML의 느슨한 문법이 들이는 모호성을 어떻게 해석하는지에 있습니다.
나란히
같은 문서, 먼저 JSON으로 보면 이렇습니다.
{
"service": "api",
"replicas": 3,
"image": "registry.example.com/api:1.4.0",
"ports": [80, 443],
"env": {
"LOG_LEVEL": "info",
"REGION": "us-east-1"
}
}
그리고 YAML로 보면 이렇습니다.
# api 서비스용 배포 설정
service: api
replicas: 3
image: registry.example.com/api:1.4.0
ports:
- 80
- 443
env:
LOG_LEVEL: info
REGION: us-east-1
YAML 버전은 중괄호, 대괄호, 키와 대부분의 문자열 둘레 따옴표, 쉼표를 떨구고, 주석을 더합니다. 구조는 구두점 대신 들여쓰기로 나릅니다. 설정을 손으로 편집하는 사람에게 이것은 진짜로 더 쾌적합니다. 함정은, 그 편의의 모든 조각이 또한 파서가 추측해야 하는 곳이고, 그 추측이 일이 잘못되는 곳이라는 것입니다.
기능 비교
| 기능 | JSON | YAML |
|---|---|---|
| 주석 | 없음(명세가 금지) | 있음(#) |
| 후행 쉼표 | 없음(명세가 금지) | 해당 없음(쉼표 없음) |
| 여러 줄 문자열 | 이스케이프 \n만 |
블록 스칼라(` |
| 앵커 / 별칭 | 없음 | 있음(&, *, <<) |
| 파싱 엄격성 | 높음(단일 문법) | 낮음(맥락 의존, 버전 의존) |
| 타입 추론 | 없음(명시적) | 공격적(암묵적) |
| 보편성 | 보편 | 넓지만 고르지 않음 |
| 공격 표면 | 최소 | 앵커, 커스텀 태그, 깊은 중첩 |
YAML의 함정
이것이 외울 가치가 있는 부분입니다. 실패가 조용하기 때문입니다.
노르웨이 문제
YAML 1.1은 긴 맨 단어 목록을 불리언으로 다룹니다. yes, no, on, off,
true, false, y, n입니다. 널리 배포된 많은 파서가 여전히 1.1 동작을
기본으로 합니다. 그래서 이것은,
country: NO
NO를 문자열 "NO"(노르웨이의 국가 코드, 그래서 이름)가 아니라 불리언
false로 파싱합니다. 같은 부류의 버그입니다.
version: 1.0 # 부동소수 1.0으로 파싱, 후행 0 떨어짐
build: 1.20 # 1.2가 됨
zip: 02134 # 선두 0: 1.1에서 8진수, 또는 2134로 벗겨짐
git_sha: 1234567 # 전부 숫자인 SHA 접두사가 정수가 됨
mac: 12:34:56 # 1.1이 콜론을 60진수로 읽음
enabled: off # 문자열 "off"가 false가 됨
우편번호, git SHA, 버전 문자열, MAC 주소, 전화번호, 일련번호처럼 숫자로 보이지만
의미상 문자열인 무엇이든 조용한 강제 변환의 후보입니다. 해법은 기계적입니다.
따옴표로 감싸세요. country: "NO", version: "1.0", zip: "02134". 따옴표는
파서 버전과 무관하게 스칼라를 문자열로 강제합니다. 그 너머로, YAML 1.2 / "코어
스키마"로 구성된 파서를 선호하세요. 불리언 집합을 true/false만으로 좁히고
60진수와 8진수 함정을 제거합니다.
의미 있는 공백
들여쓰기가 구조이므로, 들여쓰기 오류는 구조 오류입니다. 탭은 YAML에서 들여쓰기에 전혀 허용되지 않습니다. 변환하지 않은 편집기에서 온 떠도는 탭은 하드 파스 오류이고, 메시지는 좀처럼 진짜 줄을 가리키지 않습니다. 블록을 다른 들여쓰기 맥락에 복사-붙여넣기하면 의미가 바뀝니다. 두 칸을 잃은 리스트 항목은 조용히 옛 부모의 자식이 아니라 형제가 됩니다. 이 중 어느 것도 구조가 "유효"한 것으로 잡히지 않습니다. 잘 파싱되되, 의도한 것과 다른 문서로 될 뿐입니다.
앵커, 별칭, 병합 키
YAML은 노드를 한 번 정의해 재사용하게 합니다.
defaults: &defaults
retries: 3
timeout: 30
prod:
<<: *defaults
timeout: 60
&defaults가 맵을 앵커하고, *defaults가 그것을 참조하고, <<가 그것을
병합합니다. 이것은 DRY 설정에 진짜로 유용합니다. 그리고 파일이 그것에 무겁게
기대면 읽기 절벽이기도 합니다. 키의 실효 값이 이제 문서 다른 곳에 살기
때문입니다. 더 나쁘게, 재귀적 별칭은 "billion laughs" 서비스 거부 공격을
가능하게 합니다. 각각 이전 것을 참조하는 한 줌의 중첩 앵커가 지수적으로 팽창해
파스 시간에 메모리를 고갈시킵니다. 팽창을 제한하지 않는 파서는 취약합니다.
신뢰할 수 없는 소스에서 YAML을 받는다면, 별칭 팽창 제한이 있는 파서(또는 "safe"
로더)를 쓰고 앵커를 통째로 비활성화하는 것을 고려하세요.
타입 강제 변환, 일반적으로
통합하는 주제는 YAML이 타입을 추론해 도우려 하고, 추론은 추측이라는 것입니다.
방어는 모든 경우에 같습니다. 개념적으로 문자열인 무엇이든 따옴표로 감싸고,
허용적 기본값 대신 엄격한 1.2 파서로 로드하세요. 파이썬에서는 yaml.load가
아니라 yaml.safe_load이고, 다른 생태계에서는 라이브러리가 노출하는 스키마나
엄격 모드를 찾으세요.
JSON의 한계
JSON의 엄격성은 그것이 파스 시간에 거의 당신을 놀라게 하지 않는 이유입니다. 하지만 같은 엄격성이 그것을 사람이 유지보수하기에 나쁜 형식으로 만듭니다.
- 주석 없음. 명세에 없습니다, 끝입니다. 이것이 JSONC(VS Code 설정), JSON5,
그리고
// 주석핵이 존재하는 이유입니다. 주석 달 수 없는 설정은 미래의 당신이 안전하게 바꿀 수 없는 설정입니다. - 후행 쉼표 없음. 배열이나 객체에 줄을 더하면 위 줄에 쉼표를 더하는 것을 기억해야 합니다. 이것이 손 편집 JSON의 가장 흔한 오류입니다.
- 손 편집에 장황함. 중괄호, 대괄호, 따옴표 키는 사람이 편집자일 때 잡음입니다. 설정 규모에서 쌓입니다.
- 네이티브 날짜나 주석 타입 없음. 날짜는 관례상 문자열이고, 그것에 대한 메타데이터를 나르지 않습니다.
이 중 어느 것도 기계 대 기계 트래픽에는 중요하지 않습니다. 거기서는 아무도 페이로드를 손 편집하지 않습니다. 사람이 매주 편집기에서 여는 파일에는 막대하게 중요합니다.
무엇을 언제 쓸지
분할은 실패 양상을 따릅니다. 기계가 데이터를 생산·소비하고 사람이 거의 건드리지 않는 어디서나 JSON을 쓰세요. API 요청·응답 본문, 서비스 간 교환, 로그 레코드, 프로그램으로 직렬화되는 무엇이든입니다. 엄격성이 거기서 기능입니다. 정확히 하나의 해석을 원하고, 스키마가 문서이므로 주석이 필요 없습니다.
사람이 손으로 편집하는 설정에는 YAML을 쓰세요. CI 파이프라인, 쿠버네티스 매니페스트, Ansible 플레이북, 애플리케이션 설정입니다. 주석, 여러 줄 문자열, 가벼운 문법이 정확히 사람이 루프에 있는 곳에서 값을 합니다.
불편한 단서는 YAML의 함정이 정확히 이 경우에 가장 세게 문다는 것입니다. YAML이
빛나는 사람 편집 설정 파일이, 따옴표 없는 NO, 탭, 잘못 들여쓴 리스트 항목이
리뷰를 빠져나가 배포되는 바로 그 파일입니다. 그래서 YAML을 안전하게 만드는 규율,
즉 문자열다운 스칼라에 따옴표 두기, CI에서 들여쓰기 린트, 스키마 검증은 YAML이
가장 잘하는 워크로드에 타협 불가입니다.
그 검증 단계는 파이프라인에 짓는 것이 가치 있습니다. 스키마가 yaml.load가 결코
경고하지 않을 강제 변환 버그를 잡습니다. 우리는
JSON Schema로 검증하기에서 메커니즘을
다루며, 그것은 일단 파싱되면 어느 형식에든 작동합니다.
두 형식 사이에서 문서를 옮긴다면, 즉 JSON API 픽스처를 YAML 설정으로 포팅하거나 매니페스트를 도구가 요구하는 JSON으로 다시 평탄화한다면, 우리 JSON ⇄ YAML 변환기가 왕복을 처리하고 구조를 보존하며, JSON 포매터가 커밋 전에 JSON 측을 린트하고 예쁘게 출력합니다.