러스트로 갈아타기: 프론트엔드 개발자의 러스트 입문기
레거시 코드는 살리고 성능은 높이는 단계별 리팩터링 전략
한빛미디어 서평단 <나는리뷰어다> 활동을 위해서 책을 협찬 받아 작성된 서평입니다.
이 책을 고른 이유
솔직히 말하면 러스트를 써본 적이 없다. 주력 스택은 TypeScript/React이고, 평소에 메모리 관리나 컴파일러 같은 키워드는 나와 거리가 멀다고 생각했다. 그런데 요즘 프론트엔드 생태계를 보면 러스트가 자꾸 눈에 들어온다. Next.js에 내장된 SWC, Webpack을 대체하려는 Turbopack, 그리고 Go로 만들어진 esbuild까지. 내가 매일 쓰는 도구들의 내부가 슬슬 "자바스크립트가 아닌 언어"로 바뀌고 있었다.
그래서 궁금했다. 러스트가 대체 뭐길래, 기존에 잘 돌아가던 JS 도구들을 굳이 다른 언어로 다시 만드는 걸까? "러스트로 갈아타기"라는 제목이 그 질문에 대한 답을 줄 것 같았다.
리팩터링이라는 접근법
책을 펼치고 처음 느낀 건, 이 책이 "러스트를 배우자"가 아니라 "기존 코드를 러스트로 조금씩 바꿔보자"에서 출발한다는 점이었다. 1장부터 리팩터링과 재작성(rewriting)의 차이를 꽤 분명하게 나눈다.
재작성은 시스템 전체를 처음부터 다시 만드는 것이고, 리팩터링은 가장 개선이 필요한 부분만 찾아 최소한의 코드를 교체하는 것이다. 책은 후자를 권하는데, 전체를 한 번에 바꾸면 뭐가 문제인지 찾기 어렵고 기존 코드에 쌓인 수년간의 프로덕션 경험까지 잃게 되기 때문이다.
실제로 Discord는 Go로 작성된 서비스 중 지연 시간이 문제였던 부분만 러스트로 교체해 성능을 크게 개선한 사례가 있다. 이 책도 같은 맥락에서 "성능이 필요한 함수 하나만 러스트로 빼자"는 방식을 제안한다. 이 전제 덕분에 러스트를 처음 접하는 개발자도 부담 없이 읽을 수 있었다.
소유권과 대여
2장에서 러스트의 핵심인 소유권(ownership)과 대여(borrowing)를 다룬다. JS 개발자로서 이 부분이 가장 낯설었다.
자바스크립트에서는 변수를 함수에 넘기면 참조가 전달될 뿐, 원래 변수는 아무 영향 없이 계속 쓸 수 있다. 그런데 러스트에서는 값을 함수에 넘기면 소유권 자체가 이동한다. 원래 변수는 더 이상 그 값을 쓸 수 없다.
admire_art(art1); // art1의 소유권이 함수로 넘어감
admire_art(art1); // 컴파일 에러, art1은 이미 없음
자바스크립트에서는 볼 수 없는 에러다. JS의 가비지 컬렉터는 "아무도 안 쓰는 것 같으면 알아서 치워줌" 방식이라 개발자가 메모리를 신경 쓸 일이 없다. 반면 러스트는 가비지 컬렉터 없이 컴파일러가 소유권 규칙으로 메모리 안전성을 보장하기 때문에, 잘못된 코드는 실행 자체가 되지 않는다.
C 언어도 개발자가 메모리를 직접 관리하지만 실수해도 컴파일은 통과되고, 문제는 런타임에 가서야 터진다. 반면 러스트는 컴파일 단계에서 소유권 규칙 위반을 잡아내기 때문에 애초에 잘못된 코드가 실행되지 않는다. C가 1972년에 만들어져 이런 검증 개념 자체가 없었던 반면, 러스트는 2015년에 등장하면서 그동안 축적된 경험을 바탕으로 소유권 시스템을 언어 설계 단계에서 녹여냈다.
이 책에서 수명 그래프(lifetime graph)를 시각화해 보여주어 이해가 쉬웠다. 값이 언제 생성되고, 언제 유효하며, 언제 소멸하는지를 그래프로 보여주었다. 소유권이나 대여 같은 추상적인 개념을 글로만 보게 되면 머리에 잘 들어오지 않는데, 수명 그래프 덕분에 "art1이 여기서 생성되고, admire_art에 소유권이 넘어가고, 함수가 끝나면서 메모리가 해제되는구나"를 시각적으로 따라갈 수 있었다.
또 한 가지 흥미로운 건 mut 키워드다. JS에서는 const를 써야 불변이고 let이 기본적으로 가변인데, 러스트는 반대로 기본이 불변이고 mut를 명시적으로 붙여야 변경할 수 있다. "변경은 의도적으로 하라"는 언어 설계 철학이 느껴졌다. TypeScript의 readonly와 방향성은 비슷하지만, 러스트는 이걸 언어 전체에 걸쳐 강제한다는 점에서 훨씬 강력하다.
프론트엔드와 WebAssembly
9장이 프론트엔드 개발자로서 가장 흥미로웠다. 러스트로 작성한 코드를 WebAssembly(WASM)로 컴파일해서 브라우저에서 실행하는 방법을 다룬다.
책에서는 세 가지 접근법을 보여준다.
- 스크립트: 웹 페이지에서 WASM 함수를 직접 호출하는 가장 단순한 방식
- 모듈: 러스트 WASM을 npm 패키지처럼 React 프로젝트에 import해서 사용하는 방식
- 컴포넌트: Yew라는 프레임워크로 UI까지 전부 러스트로 작성하는 방식
이 중 두 번째, 모듈 방식이 가장 써볼 만하다고 느꼈다. Vite + React 프로젝트를 생성하고, 데이터 처리 같은 무거운 로직만 러스트로 작성해서 WASM 모듈로 가져오는 구조다. UI는 React(JSX)로 그대로 유지하고, 연산 함수만 러스트로 대체하는 것이다. 전부 갈아엎는 게 아니라 부분적으로 교체한다는 점에서, 1장에서 이야기한 리팩터링의 철학이 그대로 적용된다.
Yew 프레임워크도 인상적이었다. React와 비슷한 컴포넌트 기반 프레임워크인데, 상태 관리 방식이 React의 useReducer 패턴과 놀라울 정도로 닮아있다. State, Action, update(reducer), view(render)의 구조가 거의 동일하다. 프레임워크가 달라도 UI 상태 관리 패턴은 결국 같은 방향으로 수렴한다는 걸 확인할 수 있었다.
총평
이 책의 가장 큰 미덕은 "전부 바꾸지 말고, 필요한 부분만 러스트로 교체하라"는 점진적 접근법에 있다. 이미 다른 언어로 일하고 있는 개발자가 러스트를 시작하기에 부담이 적고, C FFI, 파이썬(PyO3), 자바스크립트(WASM)까지 다양한 통합 시나리오를 구체적인 예제로 다룬다는 점도 좋았다. 앞서 언급한 수명 그래프처럼 추상적인 개념을 시각적으로 풀어내는 방식도 인상적이었다.
다만 예제가 주로 C와 파이썬 중심이라, 9장의 WASM 파트가 있긴 하지만 전체 분량에서 차지하는 비중은 크지 않다. 웹 생태계에서 러스트가 어떻게 작용하는지 맛볼 수 있다는 점에서 좋았지만, 이 책의 범위상 어쩔 수 없다 하더라도 좀 더 깊이 다뤄줬으면 하는 아쉬움이 있었다. 2장에서 소유권과 대여를 다루면서 스택/힙, 메모리 할당 같은 저수준 개념이 바로 등장하는 것도 가비지 컬렉션 언어만 써온 개발자에게는 가파르게 느껴질 수 있는데, 책에서도 "주로 C/C++ 경험이 있는 독자를 대상으로 한다"고 안내하고 있으니 해당 부분은 넘어가도 된다.
누구에게 추천하는가
C나 파이썬 기반 프로젝트에서 성능 병목이 있거나, 메모리 안전성이 필요한 부분을 개선하고 싶은 개발자에게 가장 적합하다.
프론트엔드 개발자라면 9장의 WASM 파트를 중심으로 읽는 것을 추천한다. 러스트를 처음 접하더라도 1-2장에서 소유권과 대여의 기본 개념을 잡고, 9장에서 "내 React 프로젝트에 러스트를 어떻게 끼워 넣을 수 있는지"를 확인할 수 있다. 당장 러스트를 실무에 쓰지 않더라도, 내가 매일 사용하는 SWC나 Turbopack 같은 도구가 왜 러스트로 만들어졌는지 이해하는 데 도움이 된다.
러스트를 전혀 모르는 상태에서 읽어도 따라갈 수 있었지만, 편하게 읽히는 책은 아니다. 소유권 같은 개념은 JS에서는 접할 일이 없는 영역이라 낯설게 느껴질 수밖에 없다. 그래도 그 낯섦 자체가 시야를 넓혀주는 경험이었다.
#한빛미디어 #나는리뷰어다 #러스트로갈아타기