12. 실전 팁과 요령 (Tricks from the Trenches) 🟡
학습 내용:
- 한 장에 담기 힘든 실전에서 검증된 패턴들
- CI 불안정성(flake)이나 바이너리 비대화와 같은 흔한 문제들에 대한 해결책
- 오늘 바로 적용할 수 있는 빠른 성과를 내는 기술들
참조: 이 책의 모든 장 — 이 팁들은 모든 주제에 걸쳐 적용됩니다.
이 장에서는 실제 운영 환경의 Rust 코드베이스에서 반복적으로 나타나는 엔지니어링 패턴들을 모았습니다. 각 팁은 독립적이므로 순서와 상관없이 읽으셔도 좋습니다.
1. deny(warnings) 함정 피하기
문제: 소스 코드에 #![deny(warnings)]를 직접 넣으면 Clippy가 새로운 린트를 추가할 때 어제는 컴파일되던 코드가 갑자기 실패할 수 있습니다.
해결: 소스 코드 대신 CI 환경 변수(CARGO_ENCODED_RUSTFLAGS)를 사용하세요.
# CI: 소스 수정 없이 경고를 에러로 처리
env:
CARGO_ENCODED_RUSTFLAGS: "-Dwarnings"
2. 빌드는 한 번, 테스트는 어디서나
문제: cargo test는 --lib, --doc, --test 사이를 전환할 때마다 프로필이 다르기 때문에 재컴파일이 발생합니다.
해결: 유닛/통합 테스트에는 cargo nextest를 사용하고 문서 테스트는 따로 실행하세요.
cargo nextest run --workspace # 빠름: 병렬, 캐싱됨
cargo test --workspace --doc # 문서 테스트 (nextest는 지원 안 함)
3. 기능 플래그(Feature Flag) 관리
문제: 라이브러리가 기본값으로 std를 사용하지만 아무도 --no-default-features를 테스트하지 않으면, 언젠가 임베디드 사용자가 컴파일 오류를 보고하게 됩니다.
해결: CI에 cargo-hack을 추가하여 모든 기능 조합을 검사하세요.
- name: Feature matrix
run: |
cargo hack check --each-feature --no-dev-deps
4. Lock 파일: 커밋할 것인가, 무시할 것인가?
권장 규칙:
- 바이너리/애플리케이션: 예 (재현 가능한 빌드를 위해
Cargo.lock커밋) - 라이브러리: 아니요 (사용자가 버전을 선택할 수 있도록
.gitignore에 추가) - 둘 다 있는 워크스페이스: 예 (바이너리 규칙이 우선함)
5. 최적화된 의존성을 이용한 디버그 빌드
문제: serde, regex 같은 무거운 의존성들이 최적화되지 않아 디버그 빌드의 실행 속도가 너무 느립니다.
해결: 개발용 프로필에서 의존성만 최적화하도록 설정하세요.
# Cargo.toml
[profile.dev.package."*"]
opt-level = 2 # 개발 모드에서 모든 의존성 최적화
6. RUSTFLAGS vs CARGO_ENCODED_RUSTFLAGS
문제: RUSTFLAGS="-Dwarnings"는 빌드 스크립트와 proc-macro까지 모두 에러로 처리하여 외부 라이브러리 경고 때문에 빌드가 깨질 수 있습니다.
해결: **CARGO_ENCODED_RUSTFLAGS**를 사용하면 최상위 크레이트에만 적용되어 더 안전합니다.
7. cargo tree를 이용한 중복 제거 루틴
문제: syn 버전이 5개, tokio-util 버전이 3개나 있어서 컴파일이 너무 오래 걸립니다.
해결: cargo tree --duplicates로 중복을 찾고 cargo update -p <패키지>로 버전을 통합하세요. 정기적으로 이 작업을 수행하면 컴파일 시간을 5~15% 단축할 수 있습니다.
핵심 요약
- 에러 처리의 분리 — 소스 코드보다는 CI 환경에서 경고 에러 여부를 관리하세요.
- 개발 생산성 —
opt-level = 2설정을 통해 의존성 실행 속도를 높이고 개발 주기를 단축하세요. - 가벼운 의존성 —
cargo tree와cargo update를 습관화하여 컴파일 시간과 바이너리 크기를 최적화하세요. - 로컬 검증 —
cargo make나 pre-push 훅을 이용해 실수 없는 커밋 문화를 만드세요.