Go 1.27에 encoding/json/v2 정식 포함, 중복 키와 잘못된 UTF-8은 기본 거부
- Go 1.27에 encoding/json/v2와 encoding/json/jsontext 패키지가 정식 포함됨. 작년 공개한 실험 API를 피드백 반영해 안정화한 버전임
- 기본 동작이 바뀜. 잘못된 UTF-8과 중복 멤버 이름을 오류로 거부하고, nil 슬라이스와 맵을 null 대신 빈 배열이나 객체로 마샬링함
- 중복 멤버 이름은 CVE-2017-12635처럼 실제 공격에 악용된 사례가 있고, 대소문자 무시 언마샬링은 보안 취약점이자 성능 제한으로 지목됨
- 포인터 리시버에 선언한 MarshalJSON이 불일치하게 호출되는 버그는 너무 많은 애플리케이션이 현재 동작에 의존해 고칠 수 없다고 밝힘
- MarshalJSON의 []byte 할당 강제와 UnmarshalJSON의 완전한 값 요구로 인한 이중 파싱, 스트리밍 부재가 공개 API 차원의 성능 한계로 정리됨
Hacker News opinions
json.Marshal이 왜 에러를 반환하는지 모르겠음. 입력 타입이 마샬 불가능한 건 코드 버그니까 int+str이 컴파일 에러 나는 것처럼 컴파일 타임에 걸러야 하는 거 아님?
Marshal은 any를 받아서 컴파일 타임에 못 잡음. 커스텀 MarshalJSON이 에러를 반환할 수도 있고, NaN이나 Infinity 같은 non-finite float도 있고, 객체 트리 일부가 지연 로딩되다 실패하는 경우도 있음. 패닉이 필요하면 MustMarshal 래퍼를 직접 만들면 됨.
에러를 조용히 삼키는 것보단 크래시가 낫다고 봄. 코드 버그인데 유저한테 사과할 수도 없는 상황이고, 그냥 패닉 쪽이 명확함.
encoding/json/v2는 전반적으로 좋은데 MarshalIndent가 빠진 게 아쉬움. 대응 코드가 너무 복잡하고 직관적이지 않아서 마이그레이션도 힘들고, 간단히 읽기 좋은 JSON 덤프할 때도 불편함.
그 기능은 jsontext로 옮겨간 거 아님? jsontext.Value(b).Indent() 하거나 json.Marshal(v, jsontext.WithIndent(공백)) 쓰면 됨.
Dart에서 SIMD 지원 작업 중인데, 스키마로 JSON 서브셋을 제한하면 simdjson급 파서를 생성기로 뽑을 수 있을 것 같음. 정적 타입 안전성과 simdjson 성능을 같이 가져갈 수 있는데 JSON엔 아직 그런 게 없어서 이상함.
그건 staged parsing이라고 불리는 기법임. 근데 JSON 쓰는 사람 대부분은 강타입이나 스키마를 원하지 않음. 강제하고 싶으면 그냥 다른 직렬화 포맷을 쓰는 게 맞고, grpc-gateway 같은 접근이 낫다고 봄.
이제 Go는 새로운 C 컴파일러 같음. 10년 넘게 하루 18시간씩 Go를 썼는데 요즘은 모델이 Go 코드를 써주고, 6~9개월 뒤엔 직접 안 쓸 것 같음. 그래도 Go 코드이길 원하는 건 성능과 안전성을 알기 때문임.
요즘 로컬 LLM 쓰면서 Go로 돌아옴. 컨텍스트가 작을 때 Go가 제어 흐름이 단순해서 좋음. Rust는 컴파일 시간이 몇 자릿수 더 걸려서 LLM으로 같은 속도를 못 냄. Go 프로젝트 하나가 Rust면 몇 시간 걸릴 판임.
그렇게 되면 커리어 해자가 뭔지 모르겠음. Go의 장점이 주말이면 배운다는 거였는데.
에이전트 코딩을 하다 보니 손으로 코딩하는 프로젝트를 따로 남겨야겠다는 생각이 듦. 기계가 잘해도 프로그래밍 자체를 좋아하고, 코딩 실력이 녹슬면 기계를 지시하는 능력도 같이 떨어질 테니까.
6년 걸려서 JSON API 하나 나온 게 좀 놀라움. 인터페이스를 신중히 검토하는 건 좋지만 generics 때도 그랬고 Go 속도가 답답함. JSON 처리 성능이 Go의 약점으로 유명한데 왜 이렇게 오래 걸렸는지 모르겠음.