State management and ssot
State Management and SSOT Deep Dive¶
Overview¶
State management is an ownership problem first, and a UI rendering problem second. Single Source of Truth (SSOT) prevents divergence between competing state copies.
Core Concepts¶
- one canonical state owner per concern
- immutable UI state models for deterministic rendering
- explicit event pathways for mutations
- derived/read-only projections for consumers
Layer Responsibilities¶
- Presentation:
- render
UiState - emit intents/events only
- Domain/ViewModel:
- process intents into state transitions
- orchestrate use-case calls
- Data/repository:
- maintain canonical persisted state
- apply sync/cache policies
Data Flow¶
- User emits event (refresh/filter/retry).
- ViewModel processes and invokes use case.
- Use case/repository updates authoritative state.
- State stream emits new model.
- UI re-renders from latest immutable state.
Internal Architecture¶
SSOT is usually implemented with local persistence as canonical read path, then upstream refresh updates that store.
Key internal patterns:
- state reducers for predictable transitions
- state vs event channel separation
- idempotent write handling where possible
Code Examples¶
data class FeedUiState(
val isLoading: Boolean = false,
val items: List<FeedItem> = emptyList(),
val errorMessage: String? = null
)
class FeedViewModel(
private val observeFeed: ObserveFeedUseCase,
private val refreshFeed: RefreshFeedUseCase
) : ViewModel() {
private val _uiState = MutableStateFlow(FeedUiState())
val uiState: StateFlow<FeedUiState> = _uiState
}
Common Interview Questions¶
- Q: Why separate one-time events from persistent state? A: Answer by defining boundaries and ownership first, then place business rules in the correct layer, and finish with testability and change-resilience tradeoffs.
- Q: Where should SSOT live: ViewModel or repository? A: Describe data policy explicitly: freshness and invalidation rules, canonical local source, deterministic merge logic, and duplicate prevention with stable keys.
- Q: How do you prevent stale state races? A: Describe data policy explicitly: freshness and invalidation rules, canonical local source, deterministic merge logic, and duplicate prevention with stable keys.
- Q: Is immutable state always required? A: Answer by defining boundaries and ownership first, then place business rules in the correct layer, and finish with testability and change-resilience tradeoffs.
Production Considerations¶
- avoid hidden mutable singletons as state owners
- define clear state transition rules per feature
- include correlation IDs/log context for state-related failures
- test high-frequency event paths and cancellation behavior
Scalability Tradeoffs¶
- Pros:
- easier debugging and replay reasoning
- lower inconsistency risk across features
- Cons:
- more explicit modeling and boilerplate
- strict patterns can feel heavy for trivial screens
Senior-Level Insights¶
Senior-level discussions should include failure modes: state divergence, duplicate write paths, and event replay bugs. Mature teams treat state contracts as product-critical APIs.