핵심 정리
{
"user": {
"id": 1,
"profile": {
"name": "Kim",
"emails": ["a@example.com", "b@example.com"]
}
}
}문법
"함께 움직이는가"를 기준으로 중첩을 결정한다 — 단순한 편의보다 데이터 단위를 따라야 한다
JSON 중첩 구조를 설계할 때 핵심 질문은 "이 값들이 항상 함께 읽히고 함께 전달되는가"입니다. 의미상 한 단위인 데이터는 object로 묶고, 반복되는 항목은 array로 나열합니다. 예를 들어 name, email, phone이 항상 함께 전달되는 연락처 정보라면 contact object 하나로 묶는 것이 자연스럽습니다. 반면 별로 관련 없는 필드를 "그냥 같이 있으니까" 묶으면 이후 필드 단위 접근이나 부분 업데이트가 복잡해집니다.
너무 평평한 구조는 이름 충돌과 필드 관계 모호성을 만든다
모든 필드를 최상위에 두는 flat 구조는 처음에는 접근이 간단합니다. 그러나 필드가 늘어나면 이름이 충돌하거나 관계가 흐려집니다. user_name, user_email, org_name, org_email처럼 prefix를 붙이는 패턴이 나타나기 시작하면, 이미 중첩 구조가 필요하다는 신호입니다. user.name, org.email처럼 계층을 나누면 이름 공간이 분리되고, Schema 선언과 소비 코드 모두 구조를 더 명확하게 표현할 수 있습니다.
{
"user": { "name": "Kim", "email": "kim@example.com" },
"org": { "name": "Acme", "email": "info@acme.com" }
}너무 깊은 구조는 접근 경로가 길어지고 부분 갱신이 어려워진다
중첩이 깊어질수록 소비 코드에서 값에 도달하는 경로가 길어지고, 중간 단계의 존재 여부를 체크하는 null 방어 코드가 늘어납니다. a.b.c.d.e 같은 경로가 등장하면 구조를 재검토할 때입니다. 특히 REST API에서 특정 리소스를 부분적으로 업데이트할 때, 깊게 중첩된 필드 하나를 변경하기 위해 전체 상위 구조를 전송해야 하는 상황이 생깁니다. 도메인 경계가 분명한 경우에만 깊은 중첩을 쓰고, 그렇지 않다면 2~3단계 이하로 제한하는 것이 유지보수에 유리합니다.
한번 공개한 구조는 소비자가 의존한다 — "나중에 쉽게 바꿀 수 있다"는 생각이 가장 위험하다
JSON 구조를 API 응답이나 이벤트 포맷으로 공개하는 순간, 소비자가 그 모양에 의존하기 시작합니다. 나중에 flat 구조를 중첩 구조로 바꾸거나, 배열을 object로 바꾸면 소비자 코드가 깨집니다. "지금은 필드가 적으니까 flat으로 시작하자"는 판단이 이후 하위 호환성 문제를 만드는 경우가 많습니다. 지금 당장 필드가 하나뿐이어도, 나중에 관련 필드가 추가될 가능성이 있다면 처음부터 object로 감싸두는 편이 낫습니다.
선택 기준
| 상황 | 적합한 선택 |
|---|---|
| 항상 함께 전달되는 관련 필드 | object로 묶기 |
| 동일 구조의 반복 항목 | array |
| 필드가 적고 관계가 단순한 payload | flat 구조 (단, 확장 가능성 고려) |
| 도메인 경계가 명확한 하위 구조 | 중첩 object (2~3단계 권장) |
주의할 점
JSON 구조를 한 번 공개하면 소비자가 그 모양에 의존합니다. flat 구조를 나중에 중첩으로 바꾸거나 배열을 object로 변경하면 하위 호환성이 깨집니다. 지금 편해 보이는 구조보다 "나중에 필드가 추가될 때 얼마나 적게 깨지는 구조인가"를 먼저 판단해야 합니다.
{
"user_name": "Kim",
"user_email": "kim@example.com",
"org_name": "Acme",
"org_email": "info@acme.com"
}이처럼 prefix가 계속 늘어나기 시작하면 이미 중첩 object가 더 자연스러운 상태일 가능성이 높습니다. flat 구조를 유지하려고 이름만 길게 늘리는 방식은 나중에 더 자주 깨집니다.
참고 링크
3 sources