🧱 Json String Antipattern이란?

정의

Json String Antipattern은 JSON 구조를 객체로 다루지 않고 문자열(String)로 감싸서 전달하거나 저장하는 방식을 말한다. 겉보기에는 단순해 보이지만, 실제로는 검증과 유지보수에 여러 문제를 만든다.

예를 들면 아래와 같은 형태다.

{
  "value": "[{\"text\":\"10000\",\"confidence\":0.98}]"
}

이 경우 value는 JSON 배열처럼 보이지만, 실제 타입은 문자열이다.

⚠️ 왜 문제가 되는가?

1. 구조와 의미가 분리된다

  • 실제 데이터는 객체/배열인데 문자열로 숨겨진다.
  • 소비자는 JSON.parse() 같은 추가 처리를 해야 한다.
  • 타입 안정성이 떨어진다.

2. 검증이 어려워진다

  • JSON 구조로 전달되면 필드별 검증이 가능하다.
  • 문자열로 감싸면 value: string 정도만 확인된다.
  • Swagger나 API 문서에서도 구조를 제대로 표현하기 어렵다.

3. 직렬화와 역직렬화가 중복된다

  • 정상 구조라면 서버가 한 번 JSON으로 직렬화하면 끝난다.
  • 문자열로 다시 감싸면 한 번 더 파싱해야 한다.
  • 클라이언트와 서버 모두 불필요한 처리 비용이 생긴다.

4. 유지보수가 어려워진다

  • 필드가 추가되거나 구조가 바뀌면 문자열 파싱 코드도 함께 수정해야 한다.
  • 프론트엔드와 백엔드가 서로 구조를 따로 해석하게 된다.

5. 오류 추적이 힘들어진다

  • 로그를 봐도 내부 구조가 한 번 더 이스케이프되어 읽기 불편하다.
  • 파싱 실패가 어디서 났는지 추적하기 어렵다.

포인트

JSON은 구조 데이터로 다루는 것이 핵심이다. 문자열로 한 번 더 감싸면 JSON의 장점이 크게 줄어든다.

🛠️ 안 좋은 예시

{
  "value": "[\"A\",\"B\"]"
}
{
  "value": "[{\"text\":\"A\",\"confidence\":0.95}]"
}

이런 구조는 실제로는 값이 문자열이기 때문에, 소비자가 다시 파싱해야 한다.

✅ 좋은 예시

{
  "value": [
    {
      "text": "A",
      "confidence": 0.95
    }
  ]
}
{
  "value": [
    "A",
    "B"
  ]
}

🧩 대체 방법

  • JSON은 객체나 배열 그대로 전달한다.
  • DTO를 별도로 정의해서 구조를 명확하게 만든다.
  • 검증이 필요하면 필드 단위로 검증한다.
  • 저장이 필요하면 문자열이 아니라 구조화된 컬럼 또는 별도 테이블을 고려한다.

[!important] 주의 문자열이 필요한 경우도 물론 있다. 하지만 그것은 정말 텍스트로 취급해야 하는 경우에만 사용하고, JSON 구조를 숨기기 위한 용도로 쓰면 안 된다.

🔗 실무에서 자주 생기는 문제

  • Swagger 문서에서 구조가 흐려진다.
  • TypeScript/Java 같은 정적 타입 언어에서 타입 이점을 잃는다.
  • 프론트엔드가 JSON.parse()를 전제로 구현되기 쉽다.
  • 백엔드 수정 시 클라이언트까지 함께 수정해야 하는 경우가 많아진다.

🧾 정리

JSON String Antipattern은 JSON의 구조적 장점을 스스로 버리는 방식이다. 특별한 이유가 없다면 문자열로 한 번 더 감싸지 말고, 객체나 배열 그대로 전달하는 것이 좋다.


연결문서

댓글남기기