YAML 함정: 노르웨이 문제와 그 밖의 조용한 덫
YAML의 편리함은 암묵적 타입 추론에서 나오며, 바로 그 지점에서 문제가 생깁니다. 국가 코드가 false로 바뀌고, 버전 번호가 자릿수를 잃고, 시간이 정수가 됩니다. 이런 함정과 피하는 방법을 정리합니다.
YAML은 작성하기 편합니다. 중괄호도 따옴표도 없이 들여쓰기와 값만으로 표현합니다. 그 편리함은 한 가지 기능에서 나옵니다. 따옴표 없는 값의 타입을 YAML이 추측해 준다는 점입니다. 대부분의 경우 추측은 맞습니다. 하지만 나머지 경우에는 데이터를 조용히 다른 것으로 바꿔 버리고, 조용하기 때문에 운영 환경에서야 알아차리게 됩니다. 유명한 사례는 불리언이 되어 버리는 국가 코드입니다. 그러나 이것은 알아 둘 만한 더 넓은 패턴의 한 사례일 뿐입니다.
암묵적 타입 추론이 근본 원인입니다
YAML은 따옴표 없는 스칼라를 만나면 그것을 해석하려고 시도합니다. 123은
정수가 되고, true는 불리언이 되며, null은 null이 되는 식입니다.
타입을 요청한 적이 없는데도 YAML이 텍스트의 형태로부터 타입을
추론합니다. 덕분에 count: 3을 따옴표 없이 쓸 수 있지만, 동시에 아래의
모든 함정을 일으키는 원인이기도 합니다. 모든 함정에 대한 해결책은
동일합니다. 값에 따옴표를 붙이는 것입니다. 다만 언제 따옴표를 써야
하는지를 알아야 합니다.
노르웨이 문제
대표적인 사례는 국가 코드 목록입니다.
countries:
- NO # Norway
- SE # Sweden
- FR # France
YAML 1.1 명세에서 NO는 불리언 false입니다. YES, ON, OFF,
TRUE와 그 대소문자 변형도 마찬가지입니다. 그래서 노르웨이는 조용히
false가 되고, 파서는 애플리케이션이 문자열을 기대한 자리에 불리언을
건네줍니다. 같은 논리로 화학 물질 목록의 NO(일산화질소)나 사용자
이니셜도 불리언이 됩니다. 따옴표를 붙이는 것, 즉 "NO"가 해결책입니다.
YAML 1.2는 불리언을 true/false로만 좁혔지만, 많은 파서가 여전히
1.1 동작을 기본값으로 둡니다. 그러므로 안전하다고 단정할 수 없습니다.
두 글자 대문자 문자열은 따옴표가 필요한 것으로 다뤄야 합니다.
버전 번호와 60진법 함정
숫자 추론에서 비롯되는 두 가지가 더 있습니다.
- **
version: 1.20**은 부동소수점1.2로 파싱됩니다. 끝의 0이 사라지고, 둘을 구분해야 할 때1.20 == 1.2가 참이 됩니다. 버전 문자열은 항상 따옴표를 붙여야 합니다.version: "1.20"처럼 씁니다. - **
time: 22:30**은 YAML 1.1에서 60진법(sexagesimal) 정수로 읽힐 수 있습니다.22*60 + 30 = 1350이 됩니다. 시계 시각으로 의도한 필드가 의미 없는 정수가 됩니다. 따옴표를 붙이세요.
앞자리 0과 8진수 함정
id: 0755 같은 값은 **8진수(octal)**로 해석되어 10진수로 493이 될 수
있습니다. 전화번호, 우편번호, 0으로 채운 ID는 모두 앞자리 0을 잃거나
다르게 해석됩니다. CSV와 마찬가지로 앞자리 0이 의미를 갖는 값은 반드시
따옴표를 붙인 문자열이어야 합니다.
그 밖의 날카로운 모서리
- 탭은 들여쓰기에 사용할 수 없습니다. YAML은 공백을 요구하며, 끼어든 탭은 파싱 오류가 됩니다. 탭을 삽입하는 편집기는 혼란스러운 실패를 일으킵니다.
- 들여쓰기가 곧 구조입니다. 정렬이 어긋난 키는 조용히 엉뚱한 부모의 자식이 되거나 의도하지 않은 형제가 됩니다. 유효한 YAML이지만 잘못된 데이터입니다.
- 앵커와 병합 키(
&,*,<<)는 강력하지만 문서를 읽기 어렵게 만들고 파서마다 다르게 동작합니다. 아껴서 사용하세요.
대부분을 예방하는 규칙
확신이 서지 않을 때는 다른 타입으로 오인될 수 있는 문자열에 따옴표를
붙이세요. 의도치 않게 불리언이 되는 값(NO, YES, ON), 버전 번호,
시간, 0으로 채운 숫자가 그 대상입니다. 필요 없는 값에 따옴표를 붙여도
잃을 것은 없으며, 위의 모든 함정을 피할 수 있습니다. 대부분이 문자열과
식별자로 이루어진 설정 파일에서는, 손으로 조정한 숫자 파일보다 따옴표
규율이 더 중요합니다.
이런 문제를 배포 전에 잡으려면, YAML 검증기가
브라우저에서 문서를 파싱하여 구조와 오류를 보여 줍니다. 그래서 NO가
문자열로 들어왔는지 불리언으로 들어왔는지 확인할 수 있습니다. YAML이
여러분의 경우에 적합한 형식인지 아직 고민 중이라면,
JSON과 YAML 비교에서 각 형식의 위험 요소를
각각이 어울리는 상황과 견주어 다룹니다.