ToolDeck

YAML

2개 도구

데이터 직렬화 포맷

데이터 직렬화는 구조화된 데이터를 저장하거나 전송할 수 있는 형식으로 변환한 뒤 나중에 복원할 수 있도록 하는 과정입니다. 포맷마다 사람이 읽기 쉬운 정도, 기계 파싱 용이성, 표현력, 파일 크기 사이에서 서로 다른 트레이드오프를 가집니다. 올바른 포맷을 선택하면 유지보수성이 높아지고 팀 간 협업이 원활해집니다. 대규모 시스템에서는 직렬화 포맷의 선택이 성능과 운영 효율성에 직접적인 영향을 미칩니다.

JSON, YAML, TOML, XML은 소프트웨어 개발에서 가장 널리 사용되는 네 가지 텍스트 기반 직렬화 포맷입니다. 각각 특정 상황에서 최선의 선택이 되는 강점이 있으며, 트레이드오프를 이해하면 각 작업에 맞는 포맷을 선택할 수 있습니다. 예를 들어 외부 API 통신에는 JSON이, 사람이 직접 편집하는 설정 파일에는 YAML이, 그리고 문서 중심의 데이터 교환에는 XML이 각각 강점을 발휘합니다. 포맷별 생태계와 도구 지원 현황도 선택에 중요한 요소입니다.

JSON과 YAML 나란히 비교

JSON과 YAML은 동일한 데이터 모델을 표현합니다. YAML은 JSON의 엄격한 상위 집합으로, 유효한 JSON 문서는 모두 유효한 YAML이기도 합니다. 아래는 동일한 설정을 두 포맷으로 표현한 예시입니다. 두 포맷을 직접 비교해 보면 각각의 문법적 특성을 직관적으로 이해할 수 있습니다.

JSON
{
  "server": {
    "host": "localhost",
    "port": 8080,
    "debug": true
  },
  "database": {
    "url": "postgres://localhost/mydb",
    "pool": 10
  }
}
YAML
server:
  host: localhost
  port: 8080
  debug: true
database:
  url: postgres://localhost/mydb
  pool: 10

YAML은 중괄호와 대괄호 대신 들여쓰기를 사용하며, 대부분의 문자열 값에서 따옴표를 생략합니다. 이로 인해 사람이 직접 편집하는 파일에서 더 간결하고 읽기 쉽지만, 들여쓰기에 민감해집니다. 반면 JSON은 구조가 명시적이어서 자동 생성 도구나 API 페이로드에 더 적합합니다. 팀에서 두 포맷을 모두 사용한다면, 용도에 따라 명확한 규칙을 정하는 것이 혼란을 줄이는 데 도움이 됩니다.

포맷 비교

포맷가독성주석배열최적 용도
JSON★★★☆☆주석 없음기본 지원API, 데이터 교환
YAML★★★★★지원 (#)기본 지원설정 파일, IaC
TOML★★★★☆지원 (#)기본 지원앱 설정 (Rust, Python)
XML★★☆☆☆지원 (<!-- -->)반복 요소문서, SOAP, SVG

YAML의 함정

YAML은 강력하지만 개발자들을 놀라게 하는 잘 알려진 엣지 케이스가 있습니다. 가장 흔한 사례들을 소개합니다. 이러한 함정들은 대부분 YAML의 암묵적 타입 변환과 공백 민감성에서 비롯되며, 사전에 알고 있으면 디버깅 시간을 크게 줄일 수 있습니다.

노르웨이 문제

YAML 1.1에서 'NO'라는 값은 불리언 false로 해석됩니다. NO (노르웨이), OFF, FALSE, N 같은 국가 코드는 모두 false로 파싱됩니다. YAML 1.2에서는 이 문제가 수정되었지만, 많은 파서가 여전히 1.1 규칙을 사용합니다. 모호한 문자열은 항상 따옴표로 감싸세요. 특히 국제화된 설정 파일에서 언어 코드나 국가 코드를 다룰 때는 반드시 따옴표를 사용하는 것이 안전합니다.

들여쓰기 민감성

YAML은 들여쓰기로 구조를 정의합니다. 공백 하나가 더 있거나 탭 문자가 섞이면 문서의 의미가 완전히 달라질 수 있습니다. YAML에서는 들여쓰기에 탭을 사용할 수 없으며 공백만 허용됩니다. 대부분의 코드 편집기는 YAML 파일에 대해 탭을 공백으로 자동 변환하는 옵션을 제공하므로, 해당 옵션을 활성화해 두는 것이 좋습니다. 들여쓰기 오류는 런타임에서야 발견되는 경우가 많으므로, CI 파이프라인에 YAML 린터를 포함시키는 것을 권장합니다.

암묵적 타입 강제 변환

숫자, 불리언, null처럼 보이는 값은 자동으로 타입이 변환됩니다. '1.0'은 float이 되고, '2024-01-01'은 일부 파서에서 날짜 객체가 됩니다. 문자열로 유지하려는 값은 따옴표로 감싸세요. 버전 번호(예: '1.10')나 전화번호, IP 주소 등 숫자처럼 보이는 문자열은 반드시 따옴표 처리를 해야 의도치 않은 타입 변환을 막을 수 있습니다.

탭 사용 금지

YAML 명세는 들여쓰기에 탭 문자를 명시적으로 금지합니다. 공백을 탭으로 자동 변환하는 편집기는 YAML 파일을 조용히 망가뜨립니다. 편집기에서 YAML 파일에 공백을 사용하도록 설정하세요. .editorconfig 파일에 YAML 파일에 대한 탭 변환 규칙을 명시해 두면 팀 전체에서 일관성을 유지할 수 있습니다.

여러 줄 문자열 모드

YAML에는 두 가지 여러 줄 문자열 표시자가 있습니다. |(리터럴 블록, 줄바꿈 유지)과 >(폴딩 블록, 줄바꿈을 공백으로 변환)입니다. 잘못 혼용하면 아무 오류 없이 잘못된 결과가 출력됩니다. 셸 스크립트나 멀티라인 명령어를 포함할 때는 |를 사용하고, 긴 설명 텍스트를 한 줄로 합칠 때는 >를 사용하는 것이 일반적인 관례입니다. 블록 스칼라 뒤에 오는 개행 처리 방식(|-, >-)도 주의 깊게 살펴보세요.

앵커/앨리어스 순환 참조

YAML의 앵커(&)와 앨리어스(*)는 노드 재사용을 가능하게 하여 강력하지만, 순환 참조를 만들면 단순한 파서에서 무한 루프나 메모리 고갈이 발생할 수 있습니다. 신뢰할 수 없는 출처의 앵커가 포함된 YAML은 반드시 검증하세요. 보안 민감한 환경에서는 앵커 깊이 제한과 앨리어스 확장 횟수를 제한하는 파서 옵션을 활성화하는 것이 권장됩니다.

YAML 고유 기능

주석

YAML은 # 문자로 주석을 지원합니다. 이것은 설정 파일에서 JSON 대비 가장 큰 실용적 장점 중 하나로, 설정 내용을 인라인으로 문서화할 수 있습니다. 주석은 독립된 줄이나 값 뒤에 올 수 있습니다. 주석을 활용하면 복잡한 설정 값의 의도를 설명하거나, 임시로 비활성화한 옵션에 사유를 남길 수 있습니다. 잘 작성된 주석이 있는 YAML 파일은 별도의 문서 없이도 자기 설명적인 설정 파일이 됩니다.

앵커와 앨리어스

YAML에서는 &앵커이름으로 노드를 한 번 정의하고 *앵커이름으로 어디서든 재사용할 수 있습니다. 복잡한 설정에서 반복을 제거할 수 있으며, Kubernetes와 Docker Compose는 공유 서비스 정의에 앵커를 광범위하게 활용합니다. 앵커를 이용한 병합 키(<<: *앵커)를 사용하면 기본 설정을 상속하고 특정 값만 덮어쓰는 패턴을 깔끔하게 구현할 수 있습니다. 이는 환경별(개발/스테이징/프로덕션) 설정 파일을 관리할 때 특히 유용합니다.

여러 줄 문자열

YAML은 두 가지 모드의 블록 스칼라를 지원합니다. 리터럴 블록(|)은 줄바꿈을 그대로 유지하므로 스크립트나 템플릿에 유용하고, 폴딩 블록(>)은 긴 문자열을 한 줄로 합쳐 긴 산문 설명에 유용합니다. Kubernetes의 ConfigMap에서 여러 줄 설정 값을 삽입하거나, GitHub Actions에서 멀티라인 셸 스크립트를 인라인으로 정의할 때 리터럴 블록이 자주 쓰입니다. 최종 개행 처리 방식도 포맷 선택에 영향을 주므로, 정확한 출력이 필요한 경우 |-나 >- 지시자를 사용해 후행 개행을 제거하세요.

변환이 필요한 상황

CI/CD 파이프라인 설정

GitHub Actions, GitLab CI, CircleCI는 기본적으로 YAML을 사용합니다. 파이프라인 설정을 프로그래밍 방식으로 생성할 때는 JSON 객체를 만든 뒤 최종 출력을 위해 YAML로 변환하는 것이 더 편리한 경우가 많습니다. 특히 동적으로 매트릭스 빌드 설정을 생성하거나 조건별 스텝을 자동 구성할 때, JSON 중간 표현을 사용하면 코드에서 설정을 조작하기가 훨씬 쉽습니다. 변환 후 YAML 유효성 검사를 자동화 단계에 포함시키면 잘못된 파이프라인 설정으로 인한 빌드 실패를 사전에 방지할 수 있습니다.

Kubernetes 매니페스트

Kubernetes 리소스는 YAML로 정의되지만, Helm 차트 템플릿과 일부 도구는 JSON을 출력합니다. 포맷 간 변환을 통해 API 응답을 검사하고 표준 JSON 도구를 활용할 수 있습니다. kubectl 명령어는 -o json 플래그로 클러스터 상태를 JSON 형태로 출력하며, 이를 jq로 쿼리한 뒤 YAML로 역변환하여 매니페스트를 업데이트하는 워크플로가 실무에서 자주 사용됩니다.

API 응답 처리

REST API는 JSON을 반환합니다. 해당 데이터를 YAML 기반 설정 시스템(Ansible, Salt, Kubernetes)에 공급할 때, 컨버터는 수동 재포맷 없이 간극을 메워줍니다. API 응답을 YAML로 변환하면 사람이 읽기 쉬운 형태로 검토하거나, 변환된 결과를 바로 설정 관리 도구에 입력으로 전달하는 자동화 파이프라인을 구축할 수 있습니다.

설정 마이그레이션

하나의 도구에서 다른 도구로 마이그레이션할 때 설정 포맷 변환이 필요한 경우가 많습니다. JSON과 YAML 간 변환을 통해 에코시스템(Node.js → Python, Docker → Kubernetes) 간 전환을 빠르게 할 수 있습니다. 마이그레이션 과정에서 변환 도구를 사용하면 수작업으로 인한 오타나 구조적 오류를 줄이고, 전환 전후의 데이터 동등성을 자동으로 검증하는 테스트를 작성하기도 쉬워집니다.

스키마 검증 워크플로

JSON Schema 도구가 YAML Schema보다 성숙해 있습니다. 일반적인 패턴은 가독성을 위해 YAML로 설정을 작성하고, 스키마 검증을 위해 JSON으로 변환한 뒤, 배포를 위해 다시 변환하는 방식입니다. ajv, jsonschema 같은 성숙한 JSON Schema 검증 라이브러리를 활용하면 YAML 기반 설정의 유효성을 강력하게 보장할 수 있으며, 잘못된 설정이 프로덕션 환경에 배포되는 것을 방지합니다.

API와의 데이터 교환

내부 도구는 YAML 설정을 사용하고 외부 API는 JSON을 요구하는 경우가 있습니다. 빌드 파이프라인에 컨버터를 두면 중복 파일 관리 없이 두 표현을 동기화할 수 있습니다.

자주 묻는 질문

YAML은 JSON의 상위 집합인가요?

그렇습니다. YAML 1.2는 JSON의 엄격한 상위 집합으로, 유효한 JSON 문서는 모두 유효한 YAML입니다. 단, 많은 파서가 여전히 사용하는 YAML 1.1에는 유효한 JSON이 유효한 YAML 1.1이 되지 않는 엣지 케이스가 몇 가지 있습니다. 따라서 상호 운용성이 중요한 환경에서는 파서가 지원하는 YAML 버전을 명시적으로 확인하고, 필요하다면 YAML 1.2를 강제하는 설정을 사용하는 것이 안전합니다.

설정 파일에서 JSON 대신 YAML을 선택하는 이유는 무엇인가요?

YAML은 JSON이 지원하지 않는 주석을 지원합니다. 또한 깊게 중첩된 구조에서 더 간결합니다. 이 두 가지 특성 덕분에 사람이 직접 편집하는 설정 파일(Docker, Kubernetes, GitHub Actions)에서 선호되는 선택입니다. 앵커와 앨리어스를 통한 반복 제거 기능도 대규모 설정 파일 관리에서 YAML이 선호되는 추가적인 이유입니다.

TOML이란 무엇이고 언제 사용해야 하나요?

TOML(Tom's Obvious Minimal Language)은 설정 파일을 위해 설계된 포맷입니다. INI와 유사한 명확한 구문과 명시적 타입으로 모호함이 없습니다. Rust(Cargo.toml)와 Python(pyproject.toml) 프로젝트의 표준 포맷입니다. YAML의 들여쓰기 민감성이나 암묵적 타입 변환을 피하고 싶을 때 TOML이 좋은 대안이 됩니다.

JSON을 YAML로 변환하면 정보 손실이 발생하나요?

드물지만 가능성은 있습니다. 대부분의 파서에서 JSON은 키 순서를 보존합니다(명세상 비순서지만). YAML은 JSON에 상응하는 것이 없는 앵커와 태그를 지원합니다. 완벽한 왕복 변환을 위해서는 공통 부분 집합만 사용하세요. 실무에서는 키 순서 변경이나 부동소수점 표현 방식의 미묘한 차이가 비교 도구에서 불필요한 diff를 만들 수 있으므로 주의가 필요합니다.

JSON 출력에 'undefined'가 나타나는 원인은 무엇인가요?

JSON.stringify는 배열에서 undefined 값을 null로 변환하고 객체에서는 생략합니다. JSON 출력에서 예상치 못한 null이나 누락된 키가 보인다면, 소스 JavaScript 객체에 undefined 프로퍼티가 포함되어 있을 가능성이 높습니다. 이를 방지하려면 직렬화 전에 undefined 값을 명시적으로 처리하거나, JSON.stringify의 두 번째 인수(replacer 함수)를 사용해 원하는 방식으로 값을 변환하세요.

YAML 파일 안에 JSON을 사용할 수 있나요?

네. YAML이 JSON의 상위 집합이기 때문에 YAML 문서 안에 JSON 구문을 직접 포함할 수 있습니다. 이는 YAML의 들여쓰기가 복잡해질 수 있는 중첩 구조에서 간혹 활용됩니다. 실제로 일부 Kubernetes 어노테이션 값은 JSON 문자열로 인코딩된 객체를 포함하며, 이러한 혼합 방식은 도구 호환성을 유지하면서도 YAML의 가독성 이점을 활용하는 실용적인 접근법입니다.