composable-architecture
Apply functional and compositional architecture patterns when designing systems, modules, and components. Use when creating architecture definitions, designing system boundaries, defining interfaces, or building modular systems.
- Category: discovered
- Tags: github, community
- Version: 1.0.0
- Author: walid
- Downloads: 0
- Updated: 2025-11-22
Download the latest version (v1.0.0) from this page.
SKILL.md
---
name: composable-architecture
description: Apply functional and compositional architecture patterns when designing systems, modules, and components. Use when creating architecture definitions, designing system boundaries, defining interfaces, or building modular systems.
---
# Composable Architecture Patterns
Apply these patterns when designing systems for modularity, testability, and maintainability.
## Core Principles
### Functional Core, Imperative Shell
- **Pure core**: Business logic as pure functions (no side effects, immutable)
- **Imperative shell**: I/O and side effects pushed to system edges
- **Clear boundary**: Ports define interaction points between core and shell
- **Testing strategy**: Unit test the core, integration test the shell
### Composition Over Inheritance
- Build systems from small, composable functions
- Combine simple components to create complex behaviors
- Use function pipelines and modifier chaining
- Prefer data transformation over stateful mutation
## Architecture Patterns
### Hexagonal Architecture (Ports & Adapters)
```
[External World] → [Adapter] → [Port] → [Core Logic] → [Port] → [Adapter] → [External World]
```
**Components**:
- **Core**: Pure business logic, no external dependencies
- **Ports**: Interfaces defining capabilities (what the core needs/provides)
- **Adapters**: Implementations connecting to external systems
- **Primary ports**: API the application provides (commands/queries)
- **Secondary ports**: Services the application needs (persistence/messaging)
### C4 Model Hierarchy
1. **System Context**: Boundaries and external actors
2. **Container/Module**: Major architectural components
3. **Component**: Internal module structure
4. **Code**: Implementation details
**Key practices**:
- Single model, multiple views
- Version-controlled definitions
- Automated diagram generation
- Clear labeling and relationships
## Implementation Patterns
### Architecture-as-Code
Define architecture in YAML/JSON for automated generation:
```yaml
system:
name: OrderProcessing
boundary:
internal: [OrderService, PaymentService]
external: [Customer, PaymentGateway]
modules:
- id: order-service
responsibility: Manages order lifecycle
ports:
primary: [CreateOrder, GetOrderStatus]
secondary: [SaveOrder, NotifyCustomer]
```
**Benefits**:
- Version control alongside code
- CI/CD pipeline generation
- Consistent documentation
- Automated validation
### Modular Component Design
```yaml
component:
name: TireModel
module: physics
interface:
inputs: [WheelState, ChassisVelocity]
outputs: [TireForces]
behavior:
pure: true # No side effects
deterministic: true
```
**Characteristics**:
- Self-contained units
- Clear input/output contracts
- Minimal dependencies
- Independent scalability
### State Machine Composition
```
State A --event1--> State B
└---event2--> State C
```
**Best practices**:
- Pure state transition functions
- Effects separated from transitions
- Composable sub-machines
- Explicit state representation
## Interface Design
### Port Definition
```typescript
// Primary port (provided by core)
interface OrderCommands {
createOrder(items: Item[]): OrderId
cancelOrder(id: OrderId): Result
}
// Secondary port (required by core)
interface OrderRepository {
save(order: Order): Promise<void>
findById(id: OrderId): Promise<Order>
}
```
### Adapter Pattern
```typescript
// Adapter implements port interface
class PostgresOrderRepository implements OrderRepository {
// Connects pure core to impure database
}
```
## Quality Checklist
Before finalizing architecture:
- [ ] Core logic is pure (testable without mocks)
- [ ] Dependencies flow inward (no core → shell references)
- [ ] Ports defined as interfaces/contracts
- [ ] Each module has single responsibility
- [ ] Components compose without tight coupling
- [ ] State mutations isolated to shell
- [ ] Configuration externalized (YAML/env)
- [ ] Clear boundaries between layers
## Anti-patterns to Avoid
**DON'T**:
- Mix business logic with I/O operations
- Create circular dependencies between modules
- Use inheritance for code reuse (use composition)
- Scatter state mutations throughout the system
- Couple core logic to specific technologies
- Create "god" modules with multiple responsibilities
**DO**:
- Keep core logic pure and deterministic
- Push side effects to system edges
- Define clear ports between layers
- Use dependency injection for flexibility
- Test core logic without external dependencies
- Build from small, composable pieces
## Practical Application
### When designing a new system:
1. **Define boundaries**: What's inside vs. outside?
2. **Identify ports**: What capabilities needed/provided?
3. **Design pure core**: Business rules as functions
4. **Create adapters**: Connect to external world
5. **Configure composition**: Wire components together
### When refactoring existing code:
1. **Extract pure functions** from mixed logic
2. **Identify boundaries** between concerns
3. **Define interfaces** for dependencies
4. **Move I/O to edges** of the system
5. **Replace inheritance** with composition
## Example Architecture
```yaml
# Functional payment processor
system:
core:
# Pure business logic
- validatePayment(amount, card) -> ValidationResult
- calculateFees(amount, type) -> FeeBreakdown
- determineRiskScore(transaction) -> RiskScore
ports:
primary:
- ProcessPayment # Command
- GetTransaction # Query
secondary:
- PaymentGateway # External API
- TransactionStore # Persistence
- FraudDetector # External service
adapters:
inbound:
- REST API → ProcessPayment port
- GraphQL → GetTransaction port
outbound:
- StripeAdapter → PaymentGateway port
- PostgresAdapter → TransactionStore port
```
**Remember**: Composable architecture is about building systems from simple, pure, testable pieces that combine predictably. Keep the complex logic in the pure core, push the messy reality to the edges.