Development··5 min read

JS 개발자가 Rust를 배워본 3개월

소유권이라는 개념에 멘붕이 왔다. JavaScript 사고방식으로는 안 되는 언어를 배운 후기.

왜 Rust를 시작했나

솔직히 말하면 유행이었다. Deno, SWC, Turbopack, Biome 같은 JavaScript 도구들이 전부 Rust로 만들어지고 있었다. "Rust 좀 알면 이 도구들 내부를 이해할 수 있지 않을까?" 하는 생각에 시작했다.

The Rust Programming Language(일명 The Book)를 펼쳤다. 1장은 무난했다. Hello World 찍고, 변수 선언하고. "이거 그냥 C++이랑 비슷한 거 아닌가?" 싶었다.

3장에서 멘붕이 왔다.

소유권이 뭔데

JavaScript에서는 변수에 값을 넣고 다른 변수에 복사하면 둘 다 쓸 수 있다. 당연한 거라고 생각했는데 Rust는 아니다. 값의 소유자가 하나뿐이다. 다른 변수에 넘기면 원래 변수는 못 쓴다.

"이게 왜 에러야?" 를 하루에 37번쯤 외쳤다. 컴파일러가 "value moved here" 에러를 뱉어대는데, JavaScript 뇌로는 이해가 안 됐다. 1주일은 소유권과 싸우기만 했다.

(JavaScript가 얼마나 관대한 언어인지 이때 처음 느꼈다.)

라이프타임이라는 두 번째 벽

소유권을 어느 정도 이해하고 나니 라이프타임이 나왔다. 참조가 원본보다 오래 살면 안 된다는 개념인데, 'a 같은 어노테이션을 함수 시그니처에 붙여야 한다.

2주 동안 라이프타임 때문에 컴파일이 안 되는 코드를 보면서 "이걸 왜 내가 관리해야 하지? GC가 해주면 되잖아"라고 생각했다. 근데 나중에 이해하고 나니까 이게 Rust가 빠른 이유였다. GC가 없으니까 런타임 오버헤드가 없는 거다.

한 달 차: 간단한 CLI 도구를 만들었다

Markdown 파일에서 프론트매터를 추출하는 CLI 도구를 만들었다. JavaScript로 하면 30분이면 끝날 걸 Rust로 8시간 걸렸다. 문자열 처리가 JavaScript보다 훨씬 복잡하다. String&str의 차이, .to_string().as_str()의 차이. 문자열 하나 다루는 데 고려할 게 이렇게 많다니.

근데 완성된 바이너리를 실행했을 때 속도가 충격적이었다. Node.js 스크립트로 1,847개 파일을 처리하는 데 2.3초 걸리던 게 Rust로 0.04초. 57배 빨랐다.

두 달 차: 에러 핸들링에 감동했다

Rust의 Result<T, E> 타입은 에러를 무시할 수 없게 만든다. JavaScript에서는 try-catch를 까먹으면 런타임에 터지지만, Rust에서는 Result를 처리 안 하면 컴파일이 안 된다.

? 연산자로 에러를 상위로 전파하는 것도 깔끔하다. JavaScript의 throw보다 타입 안전하고, Go의 if err != nil 반복보다 간결하다.

세 달 차: 솔직한 평가

Rust가 좋은 언어라는 건 알겠다. 성능, 안전성, 에러 핸들링 전부 뛰어나다. 근데 일상적인 웹 개발에 쓰기엔 개발 속도가 너무 느리다. JavaScript로 1시간이면 만드는 걸 Rust로 하루 걸린다. 아직 내 실력이 부족한 것도 있겠지만.

CLI 도구나 성능이 중요한 라이브러리에는 Rust가 맞다. 근데 당장 API 서버를 Rust로 만들 생각은 없다. 아직은 JavaScript/TypeScript가 내 주력이고, Rust는 필요할 때 꺼내 쓰는 도구 정도로 두려고 한다.

배워서 후회하지는 않는다. 프로그래밍 자체에 대한 이해가 깊어진 느낌이 든다. 근데 3개월로 충분한지는 모르겠다.

관련 글