#핵심 패러다임 — 네 가지 기둥
버전: 0.33.0 최종 업데이트: 2026-03-15 적용 대상: ranvier-core, ranvier-macros, ranvier-runtime 카테고리: Philosophy & Architecture
Ranvier의 정체성은 함께 작동하여 Schematic 우선의 시각화 가능한 프레임워크를 만드는 네 가지 기본 개념 위에 구축됩니다.
#Transition
Transition은 하나의 상태를 다른 상태로 변환하는 순수하고 합성 가능한 함수이며, 타입이 지정된 에러로 실패할 수 있습니다. Ranvier에서 연산의 기본 단위입니다.
#주요 특성
- 순수: 동일한 입력이 주어지면 항상 동일한 출력을 생성 (비동기 I/O 제외)
- 타입 지정: 입력, 출력, 에러 타입이 명시적
- 합성 가능:
.pipe(),.fanout(),.parallel()로 Transition을 체이닝 가능 - 테스트 가능: 격리된 환경에서 쉽게 단위 테스트 가능
#왜 중요한가
- 타입 안전성: 컴파일러가 빌드 시 잘못된 상태 전환을 포착
- 합성: 단순한 Transition을 체이닝하여 복잡한 워크플로우 구축
- 가시성: 각 Transition이 Schematic 그래프에 노드로 표시
- 테스트: 인프라에 접근하지 않고 입출력 모킹 가능
#예제
use ranvier::prelude::*;
#[transition]
async fn validate_input(req: Request) -> Outcome<ValidRequest, ValidationError> {
if req.body.is_empty() {
return Outcome::err(ValidationError::EmptyBody);
}
Outcome::ok(ValidRequest::from(req))
}
#[transition]
async fn process(input: ValidRequest) -> Outcome<Response, ProcessError> {
// Business logic here
let result = compute(&input).await?;
Outcome::ok(Response::new(result))
}
// Compose:
let pipeline = Axon::simple::<AppError>()
.pipe(validate_input, process)
.build();#Outcome
Outcome은 성공 또는 실패를 나타내는 Ranvier의 결과 타입이며, 명시적 에러 타입을 가집니다. Transition 시스템과 통합됩니다.
#주요 특성
- 명시적 에러: 각 Transition이 에러 타입을 선언
- Bus 통합: 성공적인 Outcome이 Bus에 값을 저장 가능
- Schematic 메타데이터: Outcome이 시각화를 위한 메타데이터를 전달
- 편리한 사용:
?연산자 사용 가능,.map(),.and_then()등 헬퍼 메서드 제공
#왜 중요한가
- 에러 투명성: 타입 시그니처에서 모든 가능한 실패를 확인
- 우아한 성능 저하: 올바른 수준(Transition, 파이프라인, 전역)에서 에러 처리
- 디버깅: Outcome 메타데이터가 Schematic을 통한 실패 추적을 지원
#예제
// Transition returns Outcome
#[transition]
async fn fetch_user(id: UserId) -> Outcome<User, DatabaseError> {
match db.get_user(id).await {
Ok(user) => Outcome::ok(user),
Err(e) => Outcome::err(DatabaseError::from(e)),
}
}
// Outcome values automatically stored in Bus if marked
#[transition]
async fn enrich_user(user: User) -> Outcome<EnrichedUser, EnrichmentError> {
// 'user' came from Bus (injected automatically)
let profile = fetch_profile(&user).await?;
Outcome::ok(EnrichedUser { user, profile })
}#Bus
Bus는 단일 실행 컨텍스트 내에서 Transition 간에 상태를 공유하기 위한 타입 안전 인메모리 저장소입니다. "데이터를 위한 의존성 주입"이라고 생각하세요.
#주요 특성
- 타입으로 인덱싱: 타입별로 값을 저장하고 검색 (
TypeMap과 유사) - 자동 주입: Transition이 매개변수를 통해 Bus에서 값을 요청 가능
- 범위 지정: 각 실행이 자체 Bus 인스턴스를 가짐 (전역 상태 없음)
- 불변 참조: Transition이 Bus에서
&T를 수신 (소유권 이전 없음)
#왜 중요한가
- 명시적 의존성: Transition 시그니처가 필요한 데이터를 표시
- 마법 같은 전역 없음: 모든 상태가 명시적이고 실행에 범위 지정
- 테스트 가능성: 테스트를 위해 Bus에 모의 값 주입
- 컨텍스트 전파: 인증, 테넌트 ID 등을 파이프라인을 통해 전달
#예제
#[transition]
async fn authenticate(req: Request) -> Outcome<AuthContext, AuthError> {
let token = extract_token(&req)?;
let auth = validate(token).await?;
// AuthContext automatically stored in Bus for downstream transitions
Outcome::ok(auth)
}
#[transition]
async fn authorize(auth: &AuthContext) -> Outcome<(), AuthError> {
// 'auth' automatically injected from Bus (by type)
if !auth.has_role("admin") {
return Outcome::err(AuthError::Unauthorized);
}
Outcome::ok(())
}
#[transition]
async fn handle_request(auth: &AuthContext, req: &Request) -> Outcome<Response, AppError> {
// Both 'auth' and 'req' injected from Bus
Ok(Response::new(format!("Hello, {}", auth.user_id)))
}#Schematic
Schematic은 Transition 파이프라인의 방향성 비순환 그래프(DAG) 표현입니다. 런타임 실행 모델이자 VSCode와 같은 도구가 렌더링할 수 있는 시각적 산출물(JSON)입니다.
#주요 특성
- 노드: 각 Transition이 하나의 노드
- 엣지: Transition 간의 데이터 흐름
- 메타데이터: 타입, 에러 경로, 실행 통계
- 직렬화 가능: 시각화를 위해
schematic.json으로 내보내기
#왜 중요한가
- 가시성: 전체 데이터 흐름을 한눈에 파악 (VSCode Circuit 뷰에서)
- 문서화: Schematic이 곧 문서 (항상 최신 상태)
- 디버깅: 그래프를 통해 에러 추적, 어떤 노드가 실패했는지 확인
- 최적화: 병목 지점 식별, 가능한 곳에서 병렬화
#예제
// Build a schematic
let schematic = Axon::simple::<AppError>()
.pipe(authenticate, authorize, handle_request)
.build();
// Execute
let outcome = schematic.execute(request).await;
// Export to JSON (for VSCode visualization)
let json = schematic.to_json();
std::fs::write("schematic.json", json)?;#다음 단계
- 왜 Opinionated Core인가? — Ranvier가 이러한 개념을 강제하는 이유
- 경계 맵 — 코어가 끝나고 엣지가 시작되는 곳