TECH 으로 돌아가기
TECH HACKER NEWS 오늘 7분 읽기 26 READS

Flask 만든 Armin Ronacher가 serde에 던진 질문, ‘Deser’로 다시 생각하는 Rust 직렬화

Flask 만든 Armin Ronacher가 serde에 던진 질문, ‘Deser’로 다시 생각하는 Rust 직렬화
SOURCE IMAGE · HACKER NEWS
Flask 만든 Armin Ronacher가 serde에 던진 질문, ‘Deser’로 다시 생각하는 Rust 직렬화

serde, 너무 잘 만들어서 오히려 고민인 라이브러리

Rust로 뭔가를 만들어봤다면 serde를 안 써봤을 수가 없어요. 구조체에 #[derive(Serialize, Deserialize)] 한 줄만 붙이면 JSON, YAML, TOML, MessagePack 등 거의 모든 포맷으로 변환이 되니까요. Rust 생태계의 사실상 표준이고, 성능도 훌륭하죠.

그런데 Flask와 Jinja2를 만든 Armin Ronacher가 Rust 직렬화를 다시 생각해보자는 글을 올렸어요. Armin은 Rust에서도 insta(스냅샷 테스트 도구)나 MiniJinja 같은 라이브러리를 만들면서 serde를 누구보다 깊게 써온 사람이에요. 예전에도 deser라는 이름의 실험적인 크레이트를 공개하면서 비슷한 문제의식을 보여준 적이 있는데, 이번 글도 그 연장선에 있어요.

serde의 구조적인 고민들

serde가 빠른 비결은 제네릭과 단형화(monomorphization) 에 있어요. 이게 뭐냐면, Rust 컴파일러가 제네릭 코드를 타입마다 따로 복사해서 각각 최적화된 코드로 만들어주는 거예요. Vec<i32>용 코드와 Vec<String>용 코드가 따로 생기는 식이죠. 덕분에 실행 속도는 아주 빠르지만 대가가 있어요.

1. 컴파일 시간과 바이너리 크기: 구조체가 많고 포맷도 여러 개라면 대략 ‘타입 수 × 포맷 수’만큼 코드가 생겨요. 대형 프로젝트에서 serde가 만들어낸 코드가 빌드 시간의 큰 몫을 차지하는 일은 흔해요.
2. flatten과 untagged의 한계: #[serde(flatten)]이나 #[serde(untagged)]는 편리하지만, 내부적으로는 데이터를 일단 중간 형태로 버퍼링했다가 다시 해석하는 방식이에요. 그래서 느리고, 에러 메시지가 뭉개지고, 엣지 케이스 버그도 종종 보고돼요. serde의 데이터 모델이 처음부터 이런 기능을 염두에 두고 설계된 게 아니라서 생기는 문제예요.
3. 상태(컨텍스트) 전달이 어려움: 역직렬화 도중에 현재 설정값이나 문자열 인터닝 테이블 같은 외부 상태를 넘기고 싶을 때가 있어요. serde에서는 DeserializeSeed 같은 우회로를 써야 해서 꽤 번거로워요.

deser가 던지는 아이디어

Armin이 예전 deser 실험에서 보여준 방향은 대략 이래요. 먼저 동적 디스패치(dynamic dispatch) 를 적극적으로 써요. 동적 디스패치가 뭐냐면, 타입마다 코드를 복사하는 대신 트레이트 객체(dyn Trait)를 통해 어떤 함수를 부를지 실행 중에 정하는 방식이에요. 런타임 비용을 조금 내는 대신 생성되는 코드 양과 컴파일 시간을 줄일 수 있죠.

또 JSON처럼 자기 서술적(self-describing) 포맷에 집중해요. 자기 서술적 포맷은 데이터 안에 ‘이건 숫자, 이건 문자열’ 같은 구조 정보가 들어 있는 포맷이에요. bincode처럼 구조 정보가 없는 포맷까지 한 모델에 억지로 담으려던 부담을 덜어내는 거죠. 이렇게 범위를 좁히면 flatten 같은 기능을 데이터 모델 차원에서 자연스럽게 지원할 여지가 생겨요.

이번 글에서 구체적으로 어떤 API와 설계를 제안했는지는 원문을 꼭 읽어보세요. 핵심은 모든 걸 다 하는 하나의 추상화 대신 트레이드오프를 다르게 잡은 설계도 가능하다는 문제 제기예요.

업계 맥락: serde 이후를 고민하는 사람들

serde의 대안을 찾는 사람이 Armin만 있는 건 아니에요. facet은 derive로 타입의 리플렉션 정보(실행 중에 타입 구조를 들여다볼 수 있게 해주는 메타데이터)를 만들어두고, 이걸로 직렬화, 디버그 출력, 비교 같은 일을 한꺼번에 처리하려는 프로젝트예요. miniserde는 동적 디스패치로 코드 크기를 줄인 작은 대안인데, 흥미롭게도 serde 메인테이너인 dtolnay가 직접 만들었어요. 제로카피 역직렬화(데이터를 복사하지 않고 원본 버퍼를 그대로 읽는 방식)에 특화된 rkyv도 있고요.

이런 흐름은 다른 언어에서도 보여요. Go의 encoding/json/v2 논의도 그렇고, 파이썬의 Pydantic v2가 Rust 코어로 다시 작성된 것도 그래요. 직렬화는 다 끝난 문제처럼 보이지만, 실제로는 계속 다시 설계되고 있는 영역이에요.

한국 개발자에게 주는 시사점

당장 프로덕션에서 serde를 버릴 이유는 없어요. 생태계 호환성이 압도적이니까요. 그래도 이런 글은 두 가지 면에서 읽어볼 만해요. 첫째, Rust 빌드 시간이 고민인 팀이라면 코드가 어디서 부풀고 있는지 보는 눈이 생겨요. cargo llvm-lines 같은 도구로 직접 확인해보는 것도 추천해요. 둘째, 라이브러리 설계자 입장에서 정적 디스패치 vs 동적 디스패치, 범용성 vs 단순성이라는 트레이드오프를 실제 사례로 배울 수 있어요. Rust가 아니더라도 모든 API 설계에 통하는 이야기거든요.

마무리

serde는 훌륭하지만 유일한 정답은 아니에요. deser는 그 대안이 어떤 모습일 수 있는지 보여주는 실험이에요. 여러분은 serde의 flatten이나 컴파일 시간 때문에 고생해본 적 있으신가요? 런타임 비용을 조금 내고 빌드 시간을 줄이는 트레이드오프, 받아들일 만하다고 보시나요?


🔗 출처: Hacker News

SOURCE · HACKER NEWS
원문 전체 보기 → https://lucumr.pocoo.org/2026/9/29/deser/
SHARE
NEXT · CHOOSE

변화를 읽었다면,
내가 만들 수익 구조를 고릅니다.

정보를 더 모으는 데서 멈추지 않고, 광고·외주·판매·중개·구독 중 내 상황에 맞는 출발점을 정해보세요.

21가지 수익 구조 살펴보기 →
처리 중...