- Use sealed classes for commands (`sealed class Command { data class CreateUser(...) }`) and pattern match in handlers for exhaustive handling.
- Separate read and write models — query handlers return lightweight DTOs while command handlers operate on rich domain objects.
- Use coroutine channels or Flow for event streaming between command and query sides — avoid tight coupling through shared state.
- Use `suspend` functions in handlers for non-blocking command/query execution.
- Use Kotlin coroutines Flow for streaming query results.
- Validate commands with Kotlin's `require()` or a validation library before processing.
- Use separate data models for commands (input DTOs) and queries (projections).