과거 XML 지옥을 경험해 본 적이 있으신가요? 닫는 태그 하나를 빼먹어서 전체 데이터가 깨지거나, 불필요한 태그 용량 때문에 네트워크 비용이 치솟던 시절 말입니다. 다행히 우리는 JSON(JavaScript Object Notation)이라는 구원자를 만났습니다. 하지만 JSON이 "단순하다"는 이유로 대충 다루다가는 프로덕션 환경에서 예상치 못한 SyntaxError나 데이터 손실을 겪게 됩니다. 오늘은 시니어 엔지니어의 관점에서 JSON의 기초부터 실무에서 반드시 주의해야 할 '함정'까지 완벽하게 파헤쳐보겠습니다.
1. XML vs JSON: 왜 JSON이 표준이 되었나?
데이터 전송의 역사에서 JSON이 XML을 밀어낸 이유는 명확합니다. 바로 '가독성'과 '효율성'입니다. XML은 확장성이 뛰어나지만, 데이터보다 태그가 더 많은 주객전도 현상이 자주 발생합니다. 반면 JSON은 군더더기를 걷어내고 데이터 본질에 집중합니다.
| 비교 항목 | XML (과거의 유산) | JSON (현대 표준) |
|---|---|---|
| 구조 | 복잡한 트리 구조 (태그 필수) | 간결한 Key-Value 쌍 |
| 용량 | 무거움 (닫는 태그 중복) | 가벼움 (최소한의 문법) |
| 파싱 속도 | 느림 (복잡한 파서 필요) | 매우 빠름 (브라우저 네이티브 지원) |
| 타입 지원 | 모두 텍스트로 취급 | 문자열, 숫자, 배열, 불리언 구분 |
이러한 경량화 특성은 모바일 환경과 마이크로서비스 아키텍처(MSA)에서 네트워크 대역폭을 절약하는 결정적인 요인이 되었습니다.
2. 절대 틀리면 안 되는 문법 4가지 (Strict Rules)
JSON은 자바스크립트 객체 표기법에서 유래했지만, 문법은 훨씬 엄격합니다. "JS에서는 되는데 왜 JSON에서는 에러가 나지?"라는 의문이 든다면 십중팔구 아래 규칙을 어겼기 때문입니다.
- 키(Key)에 따옴표 생략 금지:
{ name: "Kim" }(X) ->{ "name": "Kim" }(O) - 작은따옴표('') 사용 금지: JSON 표준은 오직 큰따옴표("")만 허용합니다.
- 후행 쉼표(Trailing Comma) 금지: 배열이나 객체의 마지막 요소 뒤에 쉼표를 남기면 파싱 에러가 발생합니다. (IE 등 구형 브라우저나 일부 엄격한 파서에서 치명적입니다)
유효한 데이터 타입 6가지
JSON은 다음 6가지 타입만 허용합니다. undefined나 function, Date 객체는 직접 포함될 수 없습니다.
- String: "Hello World"
- Number: 10, 3.14 (8진수, 16진수 불가)
- Object: { ... }
- Array: [ ... ]
- Boolean: true, false (소문자 필수)
- Null: null
3. 실전 코딩: 직렬화와 역직렬화의 기술
개발자가 가장 많이 다루는 것은 데이터를 JSON 문자열로 바꾸는 직렬화(Serialization)와 그 반대인 역직렬화(Deserialization)입니다. 언어별 베스트 프랙티스를 알아보겠습니다.
JavaScript: JSON.stringify의 숨겨진 기능
단순히 변환만 하는 것이 아닙니다. JSON.stringify의 3번째 인자를 활용하면 가독성 좋은 포맷팅이 가능합니다. 로그를 남길 때 매우 유용합니다.
const userData = {
id: 101,
name: "DevMaster",
skills: ["React", "Node.js"],
loginAt: new Date() // 주의: Date 객체는 문자열로 변환됨
};
// 1. 일반적인 직렬화
const miniJson = JSON.stringify(userData);
// 2. 가독성을 위한 들여쓰기 (Pretty Print) - 디버깅 시 필수!
const prettyJson = JSON.stringify(userData, null, 2);
console.log(prettyJson);
/*
{
"id": 101,
"name": "DevMaster",
"skills": [
"React",
"Node.js"
],
"loginAt": "2023-11-25T00:00:00.000Z"
}
*/
외부에서 들어오는 JSON 데이터는 신뢰할 수 없습니다.
JSON.parse()는 형식이 잘못되면 즉시 앱을 멈추게 하는 에러를 던집니다. 반드시 try...catch 블록으로 감싸서 방어 코드를 작성하십시오.
Python: 한글 깨짐 방지하기
Python 백엔드 개발자라면 json.dumps 사용 시 한글이 유니코드(\uXXXX)로 깨져 보이는 현상을 겪어봤을 겁니다. 이때는 ensure_ascii=False 옵션을 켜야 합니다.
import json
data = {
"name": "홍길동",
"role": "Admin"
}
# 기본 설정: 한글이 유니코드로 변환됨
# 출력: {"name": "\ud64d\uae38\ub3d9", "role": "Admin"}
print(json.dumps(data))
# 추천 설정: 한글 있는 그대로 출력
# 출력: {"name": "홍길동", "role": "Admin"}
print(json.dumps(data, ensure_ascii=False, indent=4))
4. 시니어의 조언: JSON 사용 시 겪게 될 "진짜" 문제들
여기부터는 튜토리얼에는 잘 나오지 않는, 실무에서 대형 사고를 유발하는 이슈들입니다. 이 30%의 디테일이 여러분을 시니어 레벨로 이끌 것입니다.
① 숫자 정밀도 문제 (The BigInt Trap)
최근 데이터베이스 ID가 길어지면서(예: Twitter Snowflake ID), 64비트 정수형을 사용하는 경우가 많습니다. 문제는 JavaScript의 Number 타입이 2^53 - 1보다 큰 정수를 정확히 표현하지 못한다는 점입니다.
서버에서 9007199254740993이라는 ID를 보냈는데, 프론트엔드에서 파싱하면 9007199254740992로 미세하게 값이 바뀌어 버립니다. 이로 인해 API 호출이 404를 뱉는 황당한 버그가 발생합니다.
"id": "9007199254740993")
② 날짜(Date) 타입의 부재
JSON에는 날짜 타입이 없습니다. new Date()를 보내면 ISO 8601 형식의 문자열로 변환됩니다. 받는 쪽에서 이를 다시 날짜 객체로 변환하는 로직이 반드시 필요합니다.
③ 보안: eval() 절대 금지
아주 오래된 레거시 코드에서 JSON 파싱을 위해 eval() 함수를 쓰는 경우가 있습니다. 이는 해커에게 "내 서버를 마음대로 조종하세요"라고 대문을 열어주는 것과 같습니다. 악성 스크립트가 실행될 수 있으니, 무조건 JSON.parse()를 사용해야 합니다.
결론: 기본기가 시스템의 안정성을 결정합니다
JSON은 현대 웹 생태계의 공용어입니다. REST API부터 설정 파일(config), NoSQL DB까지 JSON이 쓰이지 않는 곳은 없습니다. 단순히 "데이터를 주고받는 형식"으로만 이해하지 말고, 엄격한 문법 규칙, 타입의 한계, 그리고 직렬화 과정에서의 엣지 케이스를 깊이 이해해야 합니다.
지금 바로 여러분의 프로젝트 코드를 열어보세요. 혹시 JSON.parse를 try-catch 없이 쓰고 있진 않나요? 큰 숫자를 그대로 Number로 받고 있진 않나요? 이 작은 차이를 보완하는 것이 견고한 시스템을 만드는 첫걸음입니다.
Post a Comment