Skip to content

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

  1. User emits event (refresh/filter/retry).
  2. ViewModel processes and invokes use case.
  3. Use case/repository updates authoritative state.
  4. State stream emits new model.
  5. 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.