clean-architecture
Clean architecture 4-layer structure (events/facades/services/repository), transaction management, dependency rules. Use when creating events, facades, services, repositories, managing transactions, asking about layer responsibilities, architectural questions, or refactoring code.
When & Why to Use This Skill
This Claude skill provides a comprehensive framework for implementing Clean Architecture through a structured 4-layer pattern: events, facades, services, and repositories. It streamlines software development by enforcing strict dependency rules, centralized transaction management, and clear separation of concerns, ensuring that codebases remain scalable, testable, and maintainable. It is particularly optimized for Rust-based applications using the AppState pattern.
Use Cases
- Case 1: Designing a new backend service from scratch using a standardized 4-layer architecture to ensure long-term code quality.
- Case 2: Implementing robust transaction management where the Facade layer coordinates multiple services while maintaining ACID properties.
- Case 3: Refactoring legacy codebases to eliminate circular dependencies and enforce strict architectural boundaries between business logic and data access.
- Case 4: Providing architectural guidance and code reviews to ensure developers adhere to constraints like function length limits and proper borrowing techniques.
| name | clean-architecture |
|---|---|
| description | Clean architecture 4-layer structure (events/facades/services/repository), transaction management, dependency rules. Use when creating events, facades, services, repositories, managing transactions, asking about layer responsibilities, architectural questions, or refactoring code. |
Clean Architecture Guide
Layer Flow
events (Presentation) → facades (Application) → services (Business Logic) → repository (Data Access)
Layer Responsibilities
events/
Discord event handlers (slash commands, buttons, reactions)
- Call facades (1:1 relationship)
- Prohibited: Direct access to Service/Repository layers
facades/
Coordinate multiple services, manage transaction boundaries
- Only layer responsible for transaction management (begin/commit/rollback)
- Compose services to implement use cases
services/
Single business operations, domain rules
- Call repositories
- Receive transactions as arguments, pass to repositories only
- Prohibited: Direct dependency on other services
repository/
Data persistence and retrieval abstraction
- DB operations with transactions (
create_with_txn, etc.) - Prohibited: Business logic implementation
Transaction Management (Critical)
Only Facade layer can manage transactions
Facade Layer
let txn = app_state.db().begin().await?;
let result = async {
service_layer_call(&txn).await?;
Ok(())
}.await;
match result {
Ok(_) => txn.commit().await?,
Err(e) => txn.rollback().await?,
}
Service Layer
pub async fn service_function(txn: &DatabaseTransaction) -> Result<()> {
repository.create_with_txn(txn, ...).await?;
Ok(()) // No commit/rollback
}
Repository Layer
pub async fn create_with_txn(&self, txn: &DatabaseTransaction, ...) -> Result<()> {
entity.insert(txn).await?;
Ok(()) // No commit/rollback
}
Dependency Injection
AppState pattern (Rust-idiomatic approach, not DI container)
- Initialize single DB connection and AppState in
main.rs - Share across all layers via PoiseData
- Constructor injection for dependencies
- Prohibited: Creating individual DB connections per layer
Architecture Constraints
Prohibited
- Cross-layer direct access (e.g., Facade → Repository direct call)
- DB operations outside transactions
- Transaction creation/commit/rollback in Service/Repository layers
- Long-held transactions
- Global variables
Code Quality Constraints
- No functions over 100 lines
- No nesting deeper than 5 levels
- Avoid unnecessary
clone(), use borrowing - Minimize
Arc<T>usage
Performance
- Use
futures::future::try_join_allfor concurrent operations