
24.09.10~13 4일 간 캐나다 몬트리올에서 열리는 RustConf 2024 에 다녀오게 되었습니다. 해당 컨퍼런스 에서 인상 깊었던 발표 들을 소개 드리고, 한국에서는 다소 생소한 UnConf 에 대한 내용도 다뤄보려고 합니다.

Rustfmt 는 RustLang의 엔진에 기본으로 포함되어있어 cargo fmt 명령어 만으로 손쉽게 코드의 formatting 을 수행할 수 있는 도구이자 프로젝트 입니다. 해당 발표는 Rustfmt 의 초기부터 개발에 참여하신 Nick Cameron 께서 진행 해주셨습니다.
시작하기에 앞서 발표자 Nick 은 formatting style 을 통일 하는것이 developer 개인으로서도 중요하지만 Project, Ecosystem 단위로 확장될 수록 그 중요성은 더 커진다고 강조합니다.
fn foo<'a, T, U>(x: &'a (T, U)) -> String
where
'a: 'static,
T: Into<String>,
U: Iterator<Item = String>,
{
...
}
위 처럼 Rust의 함수 선언은 Generics, lifetime 등 다양한 키워드들이 존재하고 경우의 수는 기하급수적으로 늘어나기 때문에 Formatting 은 어렵습니다.
foo(
a_long_arg, // comment
another_long_arg
);
foo(
a_long_arg,
// comment
another_long_arg
);
comment 역시 어느곳에나 등장할 수 있기 때문에 formatting 을 어렵게 하는 또다른 요소로 작용 합니다.
formatter 로서의 성공의 기준은 매우 높습니다. 이는 전체 생태계가 하나의 스타일과 포매터를 보편적으로 채택하는 것을 목표로 하며, 기술적 문제와 사회적 문제가 모두 포함됩니다. 두 가지 문제는 서로 얽혀 있으며, 기술적 해결책을 통해 사회적 문제를 해결할 수 있습니다.
러스트 코드 스타일을 설계하고 결정하기 위해 스타일 RFC 프로세스를 사용하였습니다. 이는 스타일 사양과 러스트 형식의 구현을 분리하여 더 많은 커뮤니티의 참여를 유도한 과정입니다. 논의와 의사결정은 공개적으로 이루어졌으며, 동의 기반으로 진행되었습니다. 스타일 팀은 공개적으로 모집되었고, 논의는 모두에게 열려 있었습니다. 팀은 객관성을 유지하기 위해 원칙을 정의하고 실험적으로 적용하였으며, 명확한 의사결정 프로세스를 통해 논의의 효율성을 높이고자 했습니다.
러스트 formatter 는 코드를 처리하여 내부 표현을 만들고 이를 기반으로 코드를 정렬합니다. 내부 표현은 평문, 토큰, 추상 구문 트리(AST) 등을 사용할 수 있으며, AST는 주석 통합의 한계가 있지만 널리 사용되는 구조입니다. Rustfmt는 다양한 스타일을 실험하고 지원할 수 있도록 설계되었으며, 높은 설정 가능성을 통해 사용자 간의 일관성을 유지하면서도 유연성을 제공합니다.
러스트 포맷 1.0은 2018 에디션의 일부로 성공적으로 출시되었습니다. 이는 커뮤니티에서 정의한 코드 스타일을 구현하고 다양한 환경에서 활용 가능한 도구입니다. 그러나 대규모 프로젝트에서는 성능 저하와 유지 관리 어려움이 발생할 수 있습니다. 특히 AST 기반 설계는 유지보수성과 성능 면에서 제약이 있었으며, 매크로 처리와 관련된 문제도 있었습니다. 향후 개선 방안으로는 AST 대신 토큰과 AST 사이의 사용자 정의 표현을 사용하는 접근법이 논의되고 있습니다. RustFormat 의 성공은 커뮤니티 규범을 존중하고, 도구와 프로세스에 대한 신뢰를 구축하며, 설치와 사용이 용이하도록 설계된 덕분이라고 볼 수 있습니다.

발표는 45분간 진행되며, 25분 동안 게임을 라이브 코딩 했습니다. 게임 개발에 Bevy 엔진을 사용하며, Rust 강의와 뉴스 채널을 운영하는 Nathan Stocks 가 진행 했습니다. 목표로 하는 'Shooting Stars'는 Rust 의 마스코트인 Ferris 가 별을 잡아 점수를 얻는 게임 입니다. 게임은 4명의 플레이어가 게임패드를 통해 경쟁하는 방식으로 설정되었으며, 아무런 베이스 없이 개발을 시작 했습니다.
VS Code로 새 게임 프로젝트를 생성하며, 빠른 개발을 위해 미리 준비된 설정을 사용했지만 대부분은 작성하는데 시간이 걸리는 메서드의 시그니처를 빠르게 작성해주는 수준일 뿐이었습니다. 나머지는 모두 직접 라이브 코딩으로 진행 되었습니다. 또한 asset 에 별과 관련된 사운드, 배경 이미지 등을 추가했고 Cargo를 통해 bevy 를 포함한 게임에 필요한 의존성을 추가 하였습니다.
Bevy 시스템을 구성하고, asset 및 cli 접근 권한을 설정 했습니다. 카메라와 배경 이미지를 생성하고 적절한 크기로 조정 했습니다. 또한, 게임 내 별을 생성하고 사운드 효과 및 물리 엔진 설정을 추가했습니다. 별은 파티클 효과와 함께 등장하며, 별을 정리 해주는 시스템을 통해 화면 아래로 사라진 별을 제거합니다.
배경 이미지 크기를 조정하기 위해 인스펙터 플러그인을 사용합니다. 배경은 3D 엔진에서 2D로 렌더링되며, 별의 효과는 파티클 시스템과 물리 플러그인을 통해 구현됩니다. 게임의 경계를 정의하여 엔티티가 화면 밖으로 벗어나지 않도록 설정합니다.
플레이어는 ID와 입력 매핑, 스코어보드 연결을 통해 게임에 참여합니다. 조이스틱 및 버튼 입력을 액션에 매핑하며, 색상과 이름을 설정한 뒤 플레이어를 스폰합니다. 플레이어의 물리 속성과 충돌 속성을 정의하여 게임 내 상호작용을 설정합니다.
이동 시스템은 플레이어의 동작을 처리하며, 달리기와 점프를 지원합니다. 조이스틱 입력을 통해 외부 힘을 설정하고, 점프는 높이를 제한하여 자연스러운 움직임을 구현합니다. 시스템은 개체의 위치와 속도를 실시간으로 업데이트하여 더블 점프를 방지합니다.

플레이어가 별을 잡는 시스템을 추가하여 충돌 이벤트를 처리합니다. 별을 잡을 때 점수를 증가시키고, 효과음을 재생하며, 파티클 효과를 표시합니다. 별은 잡힌 뒤 de-spawn 되며, 게임의 승자가 결정되면 승자 화면을 표시합니다.

발표자: Martin Pool
소프트웨어에서 버그는 피할 수 없습니다. BASIC, LOGO부터 Rust, Go, Python까지 프로그래밍 언어와 관계없이 버그는 존재할 수 있습니다. Rust는 시스템 참조와 메모리 관리를 통해 일부 버그를 줄이며, 테스트 코드의 필요성을 줄이지만 의미론적 버그는 여전히 발생합니다. 테스트는 알고리즘의 올바른 동작을 확인하지만, 테스트 코드 자체도 버그가 있을 수 있습니다. 테스트가 모든 경우를 다룰 수 없으며, 중요 부분을 놓칠 가능성이 항상 존재합니다.
테스트의 빈틈을 찾기 위해 Cargo Mutants라는 도구를 사용합니다. 이 도구는 합성 버그를 삽입하여 테스트의 커버리지를 평가합니다. 예를 들어, 심볼릭 링크 확인 함수에서 항상 true를 반환하도록 수정해도 테스트가 통과하는 문제를 발견한 사례가 있습니다. Cargo Mutants는 작은 코드 변경을 통해 테스트되지 않은 부분을 찾아내며, 코드베이스의 약점을 식별하는 데 도움을 줍니다.
Cargo Mutants는 sver과 같은 crate 에서 테스트되지 않은 부분을 발견합니다. 예를 들어, hash 함수가 모든 객체에 대해 동일한 값을 반환하거나, debug 구현이 빈 문자열을 반환해도 테스트가 통과하는 사례를 찾아냈습니다. 이는 성능 및 디버깅 문제를 유발할 수 있으며, 개선이 필요합니다. 또한, 테스트가 없는 코드의 위험성을 강조합니다.
테스트는 실제 버그를 방지하는 데 초점이 맞춰져야 합니다. Cargo Mutants의 결과를 과도하게 해석하기보다는, 중요한 코드의 테스트 커버리지를 개선하는 데 중점을 둬야 합니다. 성능에 중요한 코드는 벤치마킹이나 다른 기술을 통해 테스트할 수 있습니다.
Cargo Mutants는 Rust 코드의 테스트를 강화하기 위해 설계되었습니다. 합성된 버그를 생성하여 테스트가 얼마나 견고한지 확인하며, 이를 통해 잠재적인 문제를 발견합니다. 도구는 syn 패키지를 사용해 소스 코드를 파싱하고 AST를 생성하여 다양한 변형을 적용합니다.
Cargo Mutants는 돌연변이 커버리지를 통해 테스트의 격차를 드러내며, 테스트의 병렬화를 지원하여 CPU 활용도를 높입니다. 하지만 테스트 반복 실행으로 시간이 소요되므로 적절한 관리가 필요합니다. Cargo Mutants는 지속적 통합(CI) 환경에서 사용하기 적합하며, 커버리지 테스트와 보완적으로 사용할 수 있습니다.
Cargo Mutants는 단지 11,000줄의 코드로 구성되며, 실행 시간이 상대적으로 길지만 병렬 처리와 CI 도구를 활용하면 효율적으로 운영할 수 있습니다. 커버리지 테스트와 달리, 코드를 변경하여 테스트의 의존성을 평가하며, 퍼징이나 속성 테스트와도 차별화된 접근 방식을 제공합니다.

Chris Biscardi 는 독립 교육가이자 엔지니어로서 웹 개발에 대해 10년 이상 경험을 쌓은 전문가입니다. 웹 사이트, 웹 애플리케이션, 웹 어셈블리(Wasm)에 대해 소개하며, 러스트와 자바스크립트를 함께 사용하는 방법을 논의합니다. 그는 두 언어의 상호 운용성을 강조하며 브라우저 내에서의 Wasm 사용 방법을 설명합니다. 러스트와 자바스크립트의 결합은 웹 기술에서 필수적인 HTML, CSS와도 잘 통합됩니다.
웹 개발은 지난 10~20년 동안 빠르게 발전하였습니다. jQuery로 시작된 초기 프론트엔드 기술은 Node.js, npm, 그리고 러스트로 이어졌습니다. SPA 등장 이후 프레임워크와 번들러는 필수적인 도구가 되었으며, ECMAScript의 발전과 함께 JavaScript는 서버와 클라이언트 간 경계를 허물었습니다.
현대 웹 개발은 UI 서비스를 중심으로 복잡한 기능을 쉽게 활성화하거나 비활성화할 수 있는 프레임워크를 제공합니다. 데이터 가져오기 기술과 렌더링 방식은 정적 사이트 생성, 서버 측 렌더링, 클라이언트 측 렌더링 등을 지원합니다.
러스트와 자바스크립트는 상호보완적이며, 특히 러스트는 다음 세대의 JavaScript 툴링(예: RS Pack, Parcel)을 지원합니다. 러스트는 웹 개발에서 강력한 성능과 안정성을 제공합니다.
컴포넌트 기반 개발은 현대 웹의 핵심입니다. 러스트 기반 프레임워크 Leptos 는 데이터 가져오기와 렌더링 전략을 지원하며, 속성 매크로와 트레이트 등을 활용하여 유연한 코드를 작성할 수 있게 합니다.
Leptos 에서 데이터를 가져오는 과정은 Suspense를 통해 제어될 수 있습니다. 이 기능은 데이터가 준비될 때까지 렌더링을 지연시켜 사용성과 SEO를 동시에 개선합니다.
Leptos 에서 Server function은 클라이언트와 서버 모두에서 사용 가능하며, 폼 처리와 같은 작업에서 유용합니다. 클라이언트에서는 HTTP 요청, 서버에서는 함수 호출 형태로 동작합니다.
Leptos 역시 정적 사이트 생성, 서버 측 렌더링(SSR), 클라이언트 측 렌더링(CSR) 등의 다양한 렌더링 방식을 통해 웹 개발을 단순화하고 최적화할 수 있습니다.
렌더링 모드는 동기 및 비동기 데이터 가져오기, 스트리밍 등 다양한 옵션을 제공하며, 이러한 옵션은 Rust의 enum으로 단순하게 처리 됩니다.
Islands는 클라이언트로 전송되는 코드의 양을 줄이는 데 유용합니다. 다만 현재 Wasm에서 코드 분할은 지원되지 않아 개발자가 직접 구현해야 합니다.
Islands는 컴포넌트와 유사하지만, 클라이언트에 전송되는 코드를 줄일 수 있는 장점이 있습니다.
이는 정적 콘텐츠가 많은 경우에 유용하지만, 코드 분할과 같은 기능은 현재 Wasm에서 지원되지 않으며, 개발자가 직접 구현해야 합니다.
코드 분할은 라우트별로 코드를 분할하여 전송하는 기술로, 필요한 코드만 클라이언트에 전송할 수 있습니다.
에코시스템의 크기가 JavaScript 메타 프레임워크의 선택에 영향을 미치며, Vue, Svelte 등 다양한 옵션이 있지만 React가 현재 가장 인기 있는 프레임워크인 것은 사실 입니다. leptos는 신생 프레임워크임에도 React 의 대부분의 기능들을 포함하고 있지만 아직은 기존의 자바스크립트 코드와의 통합이 필요할 수 있습니다. 또한 그 통합은 직접 구현해야 하는 경우가 많습니다. 예를 들어, rich text editor 와 같은 도메인을 제어하는 라이브러리들은 특별한 주의가 필요합니다.
또한 leptos에서 사용하는 자바스크립트 라이브러리나 SDK는 직접 구현하거나 바인딩해야 할 수 있습니다.
Rust와 WebAssembly는 서버와 클라이언트에서 동일한 코드를 사용하는 데 유용합니다. leptos와 wasm-pack 같은 도구는 Rust 기반 웹 개발을 더욱 간소화합니다.
Rust와 Wasm을 사용하여 제작된 사례로 This Week in Bevy 라는 웹사이트가 있으며, 이는 Rust 기반 웹 개발의 가능성을 보여줍니다.

Unconf 라는 이름을 처음 들었을 때, 컨퍼런스인데 그 안에서 진행되는 프로그램명이 UnConf 인건 너무 역설적인데 대체 뭘까? 라는 생각이 들었습니다. UnConf 는 RustConf 만이 가진 전통있는 행사로서 보통 4일 간의 컨퍼런스 중, 마지막 날에 개최되고, 이름 그대로가 의미하는 바 처럼 기존의 딱딱한 형식의 컨퍼런스 발표자와 청취자의 형식을 버리고 즉석에서 토론할 주제를 화이트보드에 적은 뒤, 주제에 대해 토론할 사람끼리 모여 원형 테이블에서 대화를 나누는 형식입니다. 리드를 하는 사람이 있긴 하지만 누구나 손을 들고 토론할 기회를 가지게 되는 것이죠.
주제는 Rust 로 Interpreter를 만드는 내용이었는데 참여해보니 실제로는 반갑게도 RustPython 이라는 프로젝트에 대한 토론이었습니다. RustPython 은 한국인이 시작하여 메인테인 하고 있는 프로젝트이고 컨트리뷰션 아카데미 멘토링을 진행할때도 항상 바로 옆 강의실에서 진행을 하던 프로젝트였는데 이곳 캐나다에서 해당 프로젝트에 대한 논의가 이뤄지고 있다는 것이 신기했습니다. 리드를 하는 인원은 해당 RustPython 의 컨트리뷰터 였지만 메인테이너 못지 않게 심도있는 논의가 이루어 졌습니다. 그 중 인상깊었던 것은 python interperter 를 작성하는데 필요한 rustc 의 Tail Call Optimization(이하 TCO) 에 대한 내용 인데 이는 재귀 함수 호출에서 발생하는 성능 최적화 기법입니다. 재귀 함수에서 반복되는 tail call 을 수행할 때 불필요한 스택 프레임을 제거하여 메모리 사용을 줄이고, 성능을 개선하는 방식이지만 rustc 에는 아직 적용이 안되어 아직 RustPython 에서도 성능에 대한 한계가 있다는 내용이었습니다. TCO는 기존 스택 프레임을 덮어쓰는 방식으로 작동하므로, 함수 호출 시 필요한 스택 상의 자원 해제(Drop) 작업을 정확히 관리하기 어렵다는 단점이 있어 메모리 안정성을 중요시 하는 Rust 에는 적용이 어렵다고 합니다. 만약 함수가 반환되기 전에 소멸자를 실행해야 하는 상황이 있으면, TCO는 메모리 안전성 문제를 유발할 수 있습니다.
Leptos 의 메인테이너인 Ben Wishovich 가 주최하여 Rust 로 개발된 Web 프레임워크인 Leptos 에 대한 대화를 나눴습니다. Leptos 는 Web 개발에서 가장 인기있고 규모가 큰 NextJS 와 많이 닮아 있었습니다. SSR, CSR 을 모두 지원하고 Server function 을 지원하기 때문에 backend 구성을 추가적으로 하지 않더라도 어느 정도의 웹서비스가 가능하다는 장점까지 이미 구현이 되어있는 점이 놀랐습니다. 한국에서는 Rust 로 Web 개발을 포기하거나, 하더라도 다른 프레임웍을 사용하는 추세였는데 참가자들의 반응을 보니 북미권에서는 이미 대세인 듯한 모습 이였습니다. 저는 React 의 Framer 같은 라이브러리를 통합하는 방법에 대한 질문을 하였는데 vanilla javascript 로 구성된 프로젝트가 아닌 경우에는 통합이 어렵기 때문에 바인딩을 직접 개발할 수 밖에 없다는 답변을 받았습니다. 아직은 그 규모가 작지만 조금만 더 성장한다면 Rust 만으로도 Web개발을 하기에 충분히 매력적인 프로젝트임이 느껴졌습니다.
Tui 에 관심이 많은 Tyler Bloom 이 주최 하였습니다. 저와 일행 모두 TUI 에 관심이 많았고 특히 최근에 저는 Terminal UI 로 ERD 다이어그램을 그리는 프로젝트에 집중하고 있었기 때문에 더욱 관심 있었습니다. Tyler Bloom 는 단순히 터미널로 작성할 수 있는 블로그를 개발하는데 그치지 않고 그 터미널을 그대로 웹으로 배포하여 범용성을 높인 프로젝트를 선보였습니다. 또한 기존에 저는 cursive 라는 TUI 프레임웍을 사용했던 반면, 북미쪽에서는 ratatui 라는 프레임웍을 더 선호한다는 사실을 알게 되었습니다. cursive 는 기존 웹개발과 유사한 컴포넌트 단위의 개발을 할 수 있지만 성능이 떨어졌으며 ratatui 는 immediate 방식으로 바로 출력을 하기때문에 초기 개발시에는 러닝 커브가 있지만 계층적이며 복잡한 앱을 구현할 때는 성능상의 이점이 있었습니다.
Rust 라는 기술적으로 러닝커브가 높고 한정된 주제에 대한 컨퍼런스였음에도 1000명이 넘는 개발자들이 참여할 수 있는 장이 마련되어 있는 점이 부러웠습니다. 특히 UnConf 같은 경우는 처음 보는 사람과 자기 생각을 공유하고 토론하는 문화에 익숙하지 않은 한국인으로서 오픈소스 커뮤니티를 더욱 활성화하고 깊이 있게 개발하기 위해서는 꼭 배워야 할 문화라고 생각하게 되었습니다.