"Ok은 resolve로, Err은 reject로 도착해. 실패를 Result로 모델링해두면 프론트엔드는 깔끔하게 잡히는 에러를 공짜로 받아."
Result가 메커니즘 전부야
실패할 수 있는 command는 Result<T, E>를 돌려줘. Ok(value)를 돌려주면 프론트엔드 Promise가 value로 resolve되고, Err(e)를 돌려주면 Promise가 reject돼서 JS 쪽 try/catch나 .catch()가 받아. 따로 배울 에러 채널 같은 건 없어 — 이미 아는 그 타입이 곧 에러 프로토콜이야.
에러 타입도 직렬화돼야 해
에러도 다리를 건너니까 E는 직렬화가 돼야 해. 빠른 길은 Result<T, String>이야 — .map_err(|e| e.to_string())로 어떤 실패든 메시지로 바꿔버리면 돼. 튼튼한 길은 Serialize를 derive한 커스텀 에러 enum이고. 그러면 프론트엔드가 실패의 종류(못 찾음이냐, 권한 없음이냐, 네트워크냐)를 구분해서 다르게 반응할 수 있어. thiserror 같은 크레이트를 쓰면 그런 에러 타입을 몇 줄로 정의해.
? 연산자가 깔끔하게 유지해줘
Result를 돌려주는 command 안에서 ? 연산자는 Ok면 알맹이를 꺼내고 Err면 즉시 반환해 — From 구현이 있으면 가는 길에 에러 타입까지 바꿔주고. 겹겹이 쌓인 match 문이 위에서 아래로 읽히는 코드가 되는 거야. 커스텀 에러 enum이랑 thiserror의 #[from]을 같이 쓰면, 실패할 수 있는 연산들이 각자 뒤에 ? 하나씩만 달고 한 줄기로 이어져.