AgentSkillsCN

Engineering Conventions

工程惯例

SKILL.md

Engineering Conventions Skill (Rust Edition)

프로젝트별 엔지니어링 컨벤션을 정의하고 적용하는 Rust 가이드입니다.

언제 이 스킬을 사용하나요?

  • 새 Rust 프로젝트의 컨벤션 정립 시
  • 기존 프로젝트에 표준 적용 시
  • 팀 온보딩 시
  • 코드 리뷰 시

Rust 프로젝트 컨벤션

1. 프로젝트 구조

code
rust/
├── Cargo.toml
├── Cargo.lock             # 버전 고정 (커밋 필수)
├── .env.example           # 환경 변수 예시
├── src/
│   ├── main.rs            # 진입점
│   ├── lib.rs             # 라이브러리 루트 (선택)
│   ├── config.rs          # 환경 설정
│   ├── error.rs           # 에러 타입 정의
│   ├── response.rs        # 공통 응답 타입
│   ├── domain/            # 도메인별 모듈
│   │   ├── mod.rs
│   │   └── ai/
│   │       ├── mod.rs
│   │       ├── handler.rs
│   │       ├── service.rs
│   │       ├── dto.rs
│   │       └── prompt.rs
│   └── global/            # 전역 유틸리티
│       ├── mod.rs
│       └── middleware.rs
├── tests/                 # 통합 테스트
│   └── integration/
│       └── ai_test.rs
└── benches/               # 벤치마크 (선택)
    └── benchmark.rs

2. Cargo.toml 컨벤션

toml
[package]
name = "web3-server"
version = "0.1.0"
edition = "2021"
rust-version = "1.75"  # MSRV 명시

[dependencies]
# 웹 프레임워크
axum = "0.7"
tokio = { version = "1", features = ["full"] }
tower = "0.4"
tower-http = { version = "0.5", features = ["cors", "trace"] }

# 직렬화
serde = { version = "1", features = ["derive"] }
serde_json = "1"

# AI
async-openai = "0.18"

# 검증
validator = { version = "0.16", features = ["derive"] }

# 에러 처리
thiserror = "1"
anyhow = "1"

# 로깅
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["json"] }

# 환경 설정
dotenvy = "0.15"

[dev-dependencies]
tokio-test = "0.4"
wiremock = "0.5"  # HTTP mocking

[profile.release]
lto = true
codegen-units = 1
strip = true

3. 코딩 스타일

rust
// 모듈 선언 순서
mod config;
mod error;
mod response;
mod domain;
mod global;

// import 순서 (rustfmt가 자동 정렬)
// 1. std
use std::collections::HashMap;
use std::sync::Arc;

// 2. 외부 crate
use axum::{Router, routing::post};
use serde::{Deserialize, Serialize};

// 3. 내부 모듈
use crate::config::Config;
use crate::error::AppError;

4. Feature Flags 정책

toml
# Cargo.toml
[features]
default = []
dev = ["mock-openai"]      # 개발용 목업
mock-openai = []
rust
// 조건부 컴파일
#[cfg(feature = "mock-openai")]
pub fn create_mock_client() -> MockClient {
    // ...
}

#[cfg(not(feature = "mock-openai"))]
pub fn create_client(api_key: &str) -> Client {
    // ...
}

5. 성능 작업

bash
# 벤치마크 실행
cargo bench

# 프로파일링 (flamegraph)
cargo install flamegraph
cargo flamegraph --bin web3-server

# Release 빌드 테스트
cargo build --release
./target/release/web3-server

6. 테스트 컨벤션

rust
// 단위 테스트: 같은 파일 내
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_function_name_describes_behavior() {
        // Arrange
        let input = create_test_input();

        // Act
        let result = function_under_test(input);

        // Assert
        assert!(result.is_ok());
    }
}

// 비동기 테스트
#[tokio::test]
async fn test_async_function() {
    // ...
}

// 통합 테스트: tests/ 폴더
// tests/integration/ai_test.rs
use web3_server::domain::ai::service::AiService;

#[tokio::test]
async fn test_guide_api_integration() {
    // ...
}

Hygiene Before Commit

커밋 전 필수 체크리스트:

bash
# 1. 포맷팅
cargo fmt

# 2. 린팅
cargo clippy -- -D warnings

# 3. 테스트
cargo test

# 4. 빌드 확인
cargo build

# 5. (선택) 보안 감사
cargo audit

Git Hook 설정

bash
# .git/hooks/pre-commit
#!/bin/sh
set -e

echo "Running cargo fmt..."
cargo fmt -- --check

echo "Running cargo clippy..."
cargo clippy -- -D warnings

echo "Running cargo test..."
cargo test

echo "All checks passed!"

환경 변수 관리

bash
# .env.example (버전 관리됨)
OPENAI_API_KEY=sk-your-api-key-here
AI_SECRET_KEY=your-secret-key-here
DATABASE_URL=mysql://user:password@localhost/db
RUST_LOG=info

# .env (버전 관리 제외)
# .gitignore에 추가
rust
// config.rs
use dotenvy::dotenv;
use std::env;

pub struct Config {
    pub openai_api_key: String,
    pub ai_secret_key: String,
    pub database_url: Option<String>,
    pub rust_log: String,
}

impl Config {
    pub fn from_env() -> Result<Self, AppError> {
        dotenv().ok(); // .env 파일 로드 (없어도 OK)

        Ok(Self {
            openai_api_key: env::var("OPENAI_API_KEY")
                .map_err(|_| AppError::ConfigError("OPENAI_API_KEY not set"))?,
            ai_secret_key: env::var("AI_SECRET_KEY")
                .map_err(|_| AppError::ConfigError("AI_SECRET_KEY not set"))?,
            database_url: env::var("DATABASE_URL").ok(),
            rust_log: env::var("RUST_LOG").unwrap_or_else(|_| "info".to_string()),
        })
    }
}

Docker 설정

dockerfile
# Build stage
FROM rust:1.75-alpine AS builder

WORKDIR /app
RUN apk add --no-cache musl-dev

COPY Cargo.toml Cargo.lock ./
COPY src ./src

RUN cargo build --release --target x86_64-unknown-linux-musl

# Runtime stage
FROM alpine:3.19

RUN apk add --no-cache ca-certificates

COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/web3-server /usr/local/bin/

EXPOSE 8080
CMD ["web3-server"]

CI/CD 파이프라인

yaml
# .github/workflows/ci.yml
name: CI

on:
  push:
    branches: [main, dev]
    paths:
      - 'rust/**'
  pull_request:
    branches: [main, dev]
    paths:
      - 'rust/**'

defaults:
  run:
    working-directory: rust

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          components: rustfmt, clippy

      - name: Cache
        uses: Swatinem/rust-cache@v2

      - name: Format
        run: cargo fmt --check

      - name: Clippy
        run: cargo clippy -- -D warnings

      - name: Test
        run: cargo test

      - name: Build
        run: cargo build --release

체크리스트

컨벤션 문서 작성 시

  • 프로젝트 구조 정의
  • Cargo.toml 의존성 정책
  • 코딩 스타일 규칙
  • 테스트 컨벤션
  • 커밋 전 체크리스트
  • 환경 변수 관리 방법

컨벤션 적용 시

  • rustfmt.toml 설정
  • clippy.toml 설정 (필요시)
  • Git hooks 설정
  • CI/CD 파이프라인 구성
  • 팀 전체 공유 및 합의