[
{
"No": "1",
"Category": "Composable",
"Guideline": "Pure UI composables",
"Description": "Composable functions should only render UI",
"Do": "Accept state and callbacks",
"Don't": "Calling usecase/repo",
"Code Good": "Pure UI composable",
"Code Bad": "Business logic in UI",
"Severity": "High",
"Docs URL": "https://developer.android.com/jetpack/compose/mental-model"
},
{
"No": "2",
"Category": "Composable",
"Guideline": "Small composables",
"Description": "Each composable has single responsibility",
"Do": "Split into components",
"Don't": "Huge composable",
"Code Good": "Reusable UI",
"Code Bad": "Monolithic UI",
"Severity": "Medium",
"Docs URL": ""
},
{
"No": "3",
"Category": "Composable",
"Guideline": "Stateless by default",
"Description": "Prefer stateless composables",
"Do": "Hoist state",
"Don't": "Local mutable state",
"Code Good": "Stateless UI",
"Code Bad": "Hidden state",
"Severity": "High",
"Docs URL": "https://developer.android.com/jetpack/compose/state#state-hoisting"
},
{
"No": "4",
"Category": "State",
"Guideline": "Single source of truth",
"Description": "UI state comes from one source",
"Do": "StateFlow from VM",
"Don't": "Multiple states",
"Code Good": "Unified UiState",
"Code Bad": "Scattered state",
"Severity": "High",
"Docs URL": "https://developer.android.com/topic/architecture/ui-layer"
},
{
"No": "5",
"Category": "State",
"Guideline": "Model UI State",
"Description": "Use sealed interface/data class",
"Do": "UiState.Loading",
"Don't": "Boolean flags",
"Code Good": "Explicit state",
"Code Bad": "Flag hell",
"Severity": "High",
"Docs URL": ""
},
{
"No": "6",
"Category": "State",
"Guideline": "remember only UI state",
"Description": "remember for UI-only state",
"Do": "Scroll, animation",
"Don't": "Business state",
"Code Good": "Correct remember",
"Code Bad": "Misuse remember",
"Severity": "High",
"Docs URL": "https://developer.android.com/jetpack/compose/state"
},
{
"No": "7",
"Category": "State",
"Guideline": "rememberSaveable",
"Description": "Persist state across config",
"Do": "rememberSaveable",
"Don't": "remember",
"Code Good": "State survives",
"Code Bad": "State lost",
"Severity": "High",
"Docs URL": "https://developer.android.com/jetpack/compose/state#restore-ui-state"
},
{
"No": "8",
"Category": "State",
"Guideline": "derivedStateOf",
"Description": "Optimize recomposition",
"Do": "derivedStateOf",
"Don't": "Recompute always",
"Code Good": "Optimized",
"Code Bad": "Jank",
"Severity": "Medium",
"Docs URL": "https://developer.android.com/jetpack/compose/performance"
},
{
"No": "9",
"Category": "SideEffect",
"Guideline": "LaunchedEffect keys",
"Description": "Use correct keys",
"Do": "LaunchedEffect(id)",
"Don't": "LaunchedEffect(Unit)",
"Code Good": "Scoped effect",
"Code Bad": "Infinite loop",
"Severity": "High",
"Docs URL": "https://developer.android.com/jetpack/compose/side-effects"
},
{
"No": "10",
"Category": "SideEffect",
"Guideline": "rememberUpdatedState",
"Description": "Avoid stale lambdas",
"Do": "rememberUpdatedState",
"Don't": "Capture directly",
"Code Good": "Safe callback",
"Code Bad": "Stale state",
"Severity": "Medium",
"Docs URL": "https://developer.android.com/jetpack/compose/side-effects"
},
{
"No": "11",
"Category": "SideEffect",
"Guideline": "DisposableEffect",
"Description": "Clean up resources",
"Do": "onDispose",
"Don't": "No cleanup",
"Code Good": "No leak",
"Code Bad": "Memory leak",
"Severity": "High",
"Docs URL": ""
},
{
"No": "12",
"Category": "Architecture",
"Guideline": "Unidirectional data flow",
"Description": "UI → VM → State",
"Do": "onEvent",
"Don't": "Two-way binding",
"Code Good": "Predictable flow",
"Code Bad": "Hard debug",
"Severity": "High",
"Docs URL": "https://developer.android.com/topic/architecture"
},
{
"No": "13",
"Category": "Architecture",
"Guideline": "No business logic in UI",
"Description": "Logic belongs to VM",
"Do": "Collect state",
"Don't": "Call repo",
"Code Good": "Clean UI",
"Code Bad": "Fat UI",
"Severity": "High",
"Docs URL": ""
},
{
"No": "14",
"Category": "Architecture",
"Guideline": "Expose immutable state",
"Description": "Expose StateFlow",
"Do": "asStateFlow",
"Don't": "Mutable exposed",
"Code Good": "Safe API",
"Code Bad": "State mutation",
"Severity": "High",
"Docs URL": ""
},
{
"No": "15",
"Category": "Lifecycle",
"Guideline": "Lifecycle-aware collect",
"Description": "Use collectAsStateWithLifecycle",
"Do": "Lifecycle aware",
"Don't": "collectAsState",
"Code Good": "No leak",
"Code Bad": "Leak",
"Severity": "High",
"Docs URL": "https://developer.android.com/jetpack/compose/lifecycle"
},
{
"No": "16",
"Category": "Navigation",
"Guideline": "Event-based navigation",
"Description": "VM emits navigation event",
"Do": "VM: Channel + receiveAsFlow(), V: Collect with Dispatchers.Main.immediate",
"Don't": "Nav in UI",
"Code Good": "Decoupled nav",
"Code Bad": "Using State / SharedFlow for navigation -> event is replayed and navigation fires again (StateFlow)",
"Severity": "High",
"Docs URL": "https://developer.android.com/jetpack/compose/navigation"
},
{
"No": "17",
"Category": "Navigation",
"Guideline": "Typed routes",
"Description": "Use sealed routes",
"Do": "sealed class Route",
"Don't": "String routes",
"Code Good": "Type-safe",
"Code Bad": "Runtime crash",
"Severity": "Medium",
"Docs URL": ""
},
{
"No": "18",
"Category": "Performance",
"Guideline": "Stable parameters",
"Description": "Prefer immutable/stable params",
"Do": "@Immutable",
"Don't": "Mutable params",
"Code Good": "Stable recomposition",
"Code Bad": "Extra recomposition",
"Severity": "High",
"Docs URL": "https://developer.android.com/jetpack/compose/performance"
},
{
"No": "19",
"Category": "Performance",
"Guideline": "Use key in Lazy",
"Description": "Provide stable keys",
"Do": "key=id",
"Don't": "No key",
"Code Good": "Stable list",
"Code Bad": "Item jump",
"Severity": "High",
"Docs URL": ""
},
{
"No": "20",
"Category": "Performance",
"Guideline": "Avoid heavy work",
"Description": "No heavy computation in UI",
"Do": "Precompute in VM",
"Don't": "Compute in UI",
"Code Good": "Smooth UI",
"Code Bad": "Jank",
"Severity": "High",
"Docs URL": ""
},
{
"No": "21",
"Category": "Performance",
"Guideline": "Remember expensive objects",
"Description": "remember heavy objects",
"Do": "remember",
"Don't": "Recreate each recomposition",
"Code Good": "Efficient",
"Code Bad": "Wasteful",
"Severity": "Medium",
"Docs URL": ""
},
{
"No": "22",
"Category": "Theming",
"Guideline": "Design system",
"Description": "Centralized theme",
"Do": "Material3 tokens",
"Don't": "Hardcoded values",
"Code Good": "Consistent UI",
"Code Bad": "Inconsistent",
"Severity": "High",
"Docs URL": "https://developer.android.com/jetpack/compose/themes"
},
{
"No": "23",
"Category": "Theming",
"Guideline": "Dark mode support",
"Description": "Theme-based colors",
"Do": "colorScheme",
"Don't": "Fixed color",
"Code Good": "Adaptive UI",
"Code Bad": "Broken dark",
"Severity": "Medium",
"Docs URL": ""
},
{
"No": "24",
"Category": "Layout",
"Guideline": "Prefer Modifier over extra layouts",
"Description": "Use Modifier to adjust layout instead of adding wrapper composables",
"Do": "Use Modifier.padding()",
"Don't": "Wrap content with extra Box",
"Code Good": "Padding via modifier",
"Code Bad": "Box just for padding",
"Severity": "High",
"Docs URL": "https://developer.android.com/jetpack/compose/modifiers"
},
{
"No": "25",
"Category": "Layout",
"Guideline": "Avoid deep layout nesting",
"Description": "Deep layout trees increase measure & layout cost",
"Do": "Keep layout flat",
"Don't": "Box ? Column ? Box ? Row",
"Code Good": "Flat hierarchy",
"Code Bad": "Deep nested tree",
"Severity": "High",
"Docs URL": ""
},
{
"No": "26",
"Category": "Layout",
"Guideline": "Use Row/Column for linear layout",
"Description": "Linear layouts are simpler and more performant",
"Do": "Use Row / Column",
"Don't": "Custom layout for simple cases",
"Code Good": "Row/Column usage",
"Code Bad": "Over-engineered layout",
"Severity": "High",
"Docs URL": ""
},
{
"No": "27",
"Category": "Layout",
"Guideline": "Use Box only for overlapping content",
"Description": "Box should be used only when children overlap",
"Do": "Stack elements",
"Don't": "Use Box as Column",
"Code Good": "Proper overlay",
"Code Bad": "Misused Box",
"Severity": "Medium",
"Docs URL": ""
},
{
"No": "28",
"Category": "Layout",
"Guideline": "Prefer LazyColumn over Column scroll",
"Description": "Lazy layouts are virtualized and efficient",
"Do": "LazyColumn",
"Don't": "Column.verticalScroll()",
"Code Good": "Lazy list",
"Code Bad": "Scrollable Column",
"Severity": "High",
"Docs URL": "https://developer.android.com/jetpack/compose/lists"
},
{
"No": "29",
"Category": "Layout",
"Guideline": "Avoid nested scroll containers",
"Description": "Nested scrolling causes UX & performance issues",
"Do": "Single scroll container",
"Don't": "Scroll inside scroll",
"Code Good": "One scroll per screen",
"Code Bad": "Nested scroll",
"Severity": "High",
"Docs URL": ""
},
{
"No": "30",
"Category": "Layout",
"Guideline": "Avoid fillMaxSize by default",
"Description": "fillMaxSize may break parent constraints",
"Do": "Use exact size",
"Don't": "Fill max everywhere",
"Code Good": "Constraint-aware size",
"Code Bad": "Overfilled layout",
"Severity": "Medium",
"Docs URL": ""
},
{
"No": "31",
"Category": "Layout",
"Guideline": "Avoid intrinsic size unless necessary",
"Description": "Intrinsic measurement is expensive",
"Do": "Explicit sizing",
"Don't": "IntrinsicSize.Min",
"Code Good": "Predictable layout",
"Code Bad": "Expensive measure",
"Severity": "High",
"Docs URL": "https://developer.android.com/jetpack/compose/layout/intrinsics"
},
{
"No": "32",
"Category": "Layout",
"Guideline": "Use Arrangement and Alignment APIs",
"Description": "Declare layout intent explicitly",
"Do": "Use Arrangement / Alignment",
"Don't": "Manual spacing hacks",
"Code Good": "Declarative spacing",
"Code Bad": "Magic spacing",
"Severity": "High",
"Docs URL": ""
},
{
"No": "33",
"Category": "Layout",
"Guideline": "Extract reusable layout patterns",
"Description": "Repeated layouts should be shared",
"Do": "Create layout composable",
"Don't": "Copy-paste layouts",
"Code Good": "Reusable scaffold",
"Code Bad": "Duplicated layout",
"Severity": "High",
"Docs URL": ""
},
{
"No": "34",
"Category": "Theming",
"Guideline": "No hardcoded text style",
"Description": "Use typography",
"Do": "MaterialTheme.typography",
"Don't": "Hardcode sp",
"Code Good": "Scalable",
"Code Bad": "Inconsistent",
"Severity": "Medium",
"Docs URL": ""
},
{
"No": "35",
"Category": "Testing",
"Guideline": "Stateless UI testing",
"Description": "Composable easy to test",
"Do": "Pass state",
"Don't": "Hidden state",
"Code Good": "Testable",
"Code Bad": "Hard test",
"Severity": "High",
"Docs URL": "https://developer.android.com/jetpack/compose/testing"
},
{
"No": "36",
"Category": "Testing",
"Guideline": "Use testTag",
"Description": "Stable UI selectors",
"Do": "Modifier.testTag",
"Don't": "Find by text",
"Code Good": "Stable tests",
"Code Bad": "Flaky tests",
"Severity": "Medium",
"Docs URL": ""
},
{
"No": "37",
"Category": "Preview",
"Guideline": "Multiple previews",
"Description": "Preview multiple states",
"Do": "@Preview",
"Don't": "Single preview",
"Code Good": "Better dev UX",
"Code Bad": "Misleading",
"Severity": "Low",
"Docs URL": "https://developer.android.com/jetpack/compose/tooling/preview"
},
{
"No": "38",
"Category": "DI",
"Guideline": "Inject VM via Hilt",
"Description": "Use hiltViewModel",
"Do": "@HiltViewModel",
"Don't": "Manual VM",
"Code Good": "Clean DI",
"Code Bad": "Coupling",
"Severity": "High",
"Docs URL": "https://developer.android.com/training/dependency-injection/hilt-jetpack"
},
{
"No": "39",
"Category": "DI",
"Guideline": "No DI in UI",
"Description": "Inject in VM",
"Do": "Constructor inject",
"Don't": "Inject composable",
"Code Good": "Proper scope",
"Code Bad": "Wrong scope",
"Severity": "High",
"Docs URL": ""
},
{
"No": "40",
"Category": "Accessibility",
"Guideline": "Content description",
"Description": "Accessible UI",
"Do": "contentDescription",
"Don't": "Ignore a11y",
"Code Good": "Inclusive",
"Code Bad": "A11y fail",
"Severity": "Medium",
"Docs URL": "https://developer.android.com/jetpack/compose/accessibility"
},
{
"No": "41",
"Category": "Accessibility",
"Guideline": "Semantics",
"Description": "Use semantics API",
"Do": "Modifier.semantics",
"Don't": "None",
"Code Good": "Testable a11y",
"Code Bad": "Invisible",
"Severity": "Medium",
"Docs URL": ""
},
{
"No": "42",
"Category": "Animation",
"Guideline": "Compose animation APIs",
"Description": "Use animate*AsState",
"Do": "AnimatedVisibility",
"Don't": "Manual anim",
"Code Good": "Smooth",
"Code Bad": "Jank",
"Severity": "Medium",
"Docs URL": "https://developer.android.com/jetpack/compose/animation"
},
{
"No": "43",
"Category": "Animation",
"Guideline": "Avoid animation logic in VM",
"Description": "Animation is UI concern",
"Do": "Animate in UI",
"Don't": "Animate in VM",
"Code Good": "Correct layering",
"Code Bad": "Mixed concern",
"Severity": "Low",
"Docs URL": ""
},
{
"No": "44",
"Category": "Modularization",
"Guideline": "Feature-based UI modules",
"Description": "UI per feature",
"Do": ":feature:ui",
"Don't": "God module",
"Code Good": "Scalable",
"Code Bad": "Tight coupling",
"Severity": "High",
"Docs URL": "https://developer.android.com/topic/modularization"
},
{
"No": "45",
"Category": "Modularization",
"Guideline": "Public UI contracts",
"Description": "Expose minimal UI API",
"Do": "Interface/Route",
"Don't": "Expose impl",
"Code Good": "Encapsulated",
"Code Bad": "Leaky module",
"Severity": "Medium",
"Docs URL": ""
},
{
"No": "46",
"Category": "State",
"Guideline": "Snapshot state only",
"Description": "Use Compose state",
"Do": "mutableStateOf",
"Don't": "Custom observable",
"Code Good": "Compose aware",
"Code Bad": "Buggy UI",
"Severity": "Medium",
"Docs URL": ""
},
{
"No": "47",
"Category": "State",
"Guideline": "Avoid mutable collections",
"Description": "Immutable list/map",
"Do": "PersistentList",
"Don't": "MutableList",
"Code Good": "Stable UI",
"Code Bad": "Silent bug",
"Severity": "High",
"Docs URL": ""
},
{
"No": "48",
"Category": "Lifecycle",
"Guideline": "RememberCoroutineScope usage",
"Description": "Only for UI jobs",
"Do": "UI coroutine",
"Don't": "Long jobs",
"Code Good": "Scoped job",
"Code Bad": "Leak",
"Severity": "Medium",
"Docs URL": "https://developer.android.com/jetpack/compose/side-effects#remembercoroutinescope"
},
{
"No": "49",
"Category": "Interop",
"Guideline": "Interop View carefully",
"Description": "Use AndroidView",
"Do": "Isolated usage",
"Don't": "Mix everywhere",
"Code Good": "Safe interop",
"Code Bad": "Messy UI",
"Severity": "Low",
"Docs URL": "https://developer.android.com/jetpack/compose/interop"
},
{
"No": "50",
"Category": "Interop",
"Guideline": "Avoid legacy patterns",
"Description": "No LiveData in UI",
"Do": "StateFlow",
"Don't": "LiveData",
"Code Good": "Modern stack",
"Code Bad": "Legacy debt",
"Severity": "Medium",
"Docs URL": ""
},
{
"No": "51",
"Category": "Debug",
"Guideline": "Use layout inspector",
"Description": "Inspect recomposition",
"Do": "Tools",
"Don't": "Blind debug",
"Code Good": "Fast debug",
"Code Bad": "Guessing",
"Severity": "Low",
"Docs URL": "https://developer.android.com/studio/debug/layout-inspector"
},
{
"No": "52",
"Category": "Debug",
"Guideline": "Enable recomposition counts",
"Description": "Track recomposition",
"Do": "Debug flags",
"Don't": "Ignore",
"Code Good": "Performance aware",
"Code Bad": "Hidden jank",
"Severity": "Low",
"Docs URL": ""
}
]