What is Clean Architecture?
Clean Architecture is a software design philosophy that emphasizes separation of concerns and independence of frameworks, UI, databases, and external agencies. The Muun Wallet follows this pattern to achieve:- Testability: Business logic can be tested without UI or database
- Maintainability: Clear boundaries make code easier to understand and modify
- Flexibility: Easy to swap implementations (e.g., change database or UI framework)
- Scalability: Well-organized code that grows predictably
Muun’s implementation is based on Fernando Cejas’s Android Clean Architecture approach, adapted for a Bitcoin wallet’s security requirements.
Core Principles
1. Dependency Rule
The fundamental rule of clean architecture: dependencies point inward.Critical Security Practice: The presentation layer never directly accesses the data layer. This prevents UI code from bypassing business logic and security checks.
2. Abstraction at Boundaries
Layers communicate through interfaces and abstractions:- Domain defines interfaces for data operations
- Data layer implements these interfaces
- Presentation depends on domain abstractions, not concrete implementations
3. Independent of Frameworks
Business logic doesn’t depend on Android framework:- Domain models are pure Java/Kotlin classes
- Business rules work without Activity or Context
- Can be tested without Android runtime
4. Independent of UI
Business logic is separate from UI:- Changing UI doesn’t affect business rules
- Same domain logic could power different UIs (mobile, web, CLI)
- UI is replaceable without touching core logic
Layer Responsibilities
Presentation Layer: What Users See
Package:io.muun.apollo.presentation
Responsibilities:
- Display data to users
- Capture user input
- Respond to user interactions
- Navigate between screens
- Make business decisions
- Access database directly
- Call network APIs directly
- Perform cryptographic operations
Domain Layer: Business Logic Core
Package:io.muun.apollo.domain
Responsibilities:
- Implement business rules
- Define domain models
- Orchestrate data operations
- Make decisions about when to sign transactions
- Validate business constraints
- Know about Activities or Views
- Know about database implementation
- Know about network protocol details
Data Layer: External World Gateway
Package:io.muun.apollo.data
Responsibilities:
- Persist data to database
- Fetch data from network
- Interact with Android OS
- Cache and synchronize data
- Make business decisions
- Know about UI components
- Implement business validation
Communication Between Layers
Using Actions (Use Cases)
Actions are the primary way to execute business logic. They follow a consistent pattern:domain/action/SigninActions.java:11
Async Actions with RxJava
Many actions are asynchronous and return RxJava Observables:domain/action/base/BaseAsyncAction1.java:5
Repository Pattern
Repositories in the data layer provide clean interfaces:- Hide implementation details (SQL, HTTP, etc.)
- Return domain models, not database entities
- Use RxJava for async operations
Dependency Injection with Dagger
Muun uses Dagger 2 for dependency injection, which enforces clean architecture:Dagger’s compile-time dependency graph ensures that the dependency rule isn’t violated. If presentation tried to inject a data component directly, the build would fail.
Testing Strategy
Unit Tests
Clean architecture makes unit testing straightforward:- Domain layer: Test actions with mocked repositories
- Data layer: Test repositories with mocked DAOs/APIs
- Presentation layer: Test presenters with mocked actions
Integration Tests
- Test domain + data together with real database
- Test domain + data with mocked network
- Test full stack with test doubles
What Gets Tested
Security Benefits
Clean architecture provides security advantages for a Bitcoin wallet:Key Security Checkpoints
- Centralized Validation: All business rules in domain layer
- No Bypass Routes: UI can’t skip validation by accessing data directly
- Auditable: Security-critical code is isolated in domain/common
- Testable: Cryptographic operations can be thoroughly tested
Auditing Focus Areas
When auditing Muun’s code for security:- Common Module: Key handling and transaction crafting
- Most cryptographic operations
- Bitcoin protocol implementation
- Data Layer: Keystore and data persistence
- Where keys are stored (secure storage)
- Data serialization/deserialization
- Domain Layer: When to sign what
- Authorization logic
- Transaction approval flow
- User verification
Anti-Patterns to Avoid
Benefits for Muun Wallet
Maintainability
- Clear file organization by feature and layer
- Easy to find where logic belongs
- Changes isolated to single layer
Security
- Critical code isolated and auditable
- No accidental bypass of security checks
- Testable cryptographic operations
Scalability
- New features follow established patterns
- Multiple developers can work on different layers
- Clear interfaces between components
Flexibility
- Can swap database implementation
- Can change network layer
- UI can be redesigned without touching business logic
Further Reading
Fernando Cejas - Clean Architecture
Original blog post that inspired Muun’s architecture
Clean Architecture Evolution
Follow-up post on clean architecture patterns