"Ok은 resolve가 돼. Err은 reject가 돼. 실패를 Result로 모델링하면 프론트엔드는 깔끔하고 catch 가능한 에러를 공짜로 받아."
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이야. 그러면 프론트엔드가 실패의 종류(not-found vs permission-denied vs network)를 구분해 다르게 반응할 수 있어. thiserror 같은 크레이트가 그런 에러 타입 정의를 몇 줄로 만들어줘.
? 연산자가 깔끔하게 유지해
Result를 반환하는 command 안에서 ? 연산자는 Ok를 풀거나 Err로 조기 반환해 — From impl이 있으면 가는 길에 에러를 변환하면서. 이게 중첩 match 문을 선형의 읽기 쉬운 코드로 바꿔. 커스텀 에러 enum이랑 thiserror의 #[from]이 있으면, 실패 가능한 연산 체인이 각각 뒤에 ?를 달고 위에서 아래로 읽혀.