mobile-best-practices 1.7.0 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/data/anti-patterns.csv +122 -121
- package/assets/data/code-snippets.csv +314 -81
- package/assets/data/design-patterns.csv +113 -118
- package/assets/data/gradle-deps.csv +1 -1
- package/assets/data/libraries.csv +1 -1
- package/assets/data/performance.csv +12 -12
- package/assets/data/platforms/android.csv +312 -424
- package/assets/data/platforms/ios.csv +26 -26
- package/assets/data/platforms/react-native.csv +1 -1
- package/assets/data/security.csv +202 -202
- package/assets/data/testing.csv +3 -3
- package/assets/data/ui-patterns.csv +96 -92
- package/assets/scripts/core.py +377 -26
- package/assets/scripts/search.py +68 -17
- package/assets/skills/all.md +5 -3
- package/assets/skills/android-xml.md +1 -1
- package/assets/skills/android.md +76 -28
- package/assets/skills/flutter.md +4 -2
- package/assets/skills/ios.md +4 -2
- package/assets/skills/react-native.md +4 -2
- package/package.json +1 -1
- package/assets/scripts/__pycache__/core.cpython-314.pyc +0 -0
|
@@ -1,121 +1,122 @@
|
|
|
1
|
-
Name,Platform,Category,Severity,Keywords,Description,Bad Example,Good Example,Why Bad,Fix,Reference URL
|
|
2
|
-
God Activity,Android,Architecture,Critical,god activity massive class monolith,Activity with 1000+ lines handling UI business logic and data,class MainActivity { fun fetchData() { db.query() } fun updateUI() },Split into ViewModel + Repository + Composable screens,Violates SRP unmaintainable untestable,Extract ViewModel for logic Repository for data,https://developer.android.com/topic/architecture
|
|
3
|
-
Massive ViewController,iOS,Architecture,Critical,massive viewcontroller mvc god class,ViewController handling all responsibilities,class HomeVC { func callAPI() func parseJSON() func updateUI() },Use MVVM-C with separate ViewModel and Coordinator,Untestable unmaintainable violates SRP,Extract ViewModel Coordinator for navigation,https://developer.apple.com/documentation/swiftui
|
|
4
|
-
Business Logic in Widget,Flutter,Architecture,High,logic widget bloc provider build,Business logic directly in widget build method,Widget build() { final data = http.get(...); return Text(data); },Use BLoC or Provider for business logic separation,Tight coupling impossible to test re-fetches on rebuild,Move logic to BLoC/Cubit inject via BlocProvider,https://bloclibrary.dev/
|
|
5
|
-
Prop Drilling,React Native,Architecture,High,prop drilling passing props deep nesting,Passing props through many component layers,<A data={d}><B data={d}><C data={d}><D data={d}/></C></B></A>,Use Context or state management library,Makes refactoring painful components tightly coupled,Use React Context or Zustand/Redux for shared state,https://react.dev/learn/passing-data-deeply-with-context
|
|
6
|
-
Circular Dependencies,All,Architecture,High,circular dependency import cycle module,Module A depends on B depends on A,moduleA imports moduleB; moduleB imports moduleA,Use dependency inversion interface abstraction,Build failures unclear ownership infinite loops,Introduce interface in shared module,
|
|
7
|
-
Skip Layers in Clean Arch,All,Architecture,Medium,skip layer clean architecture shortcut domain,Presentation layer directly accessing data layer,ViewModel calls Repository bypassing UseCase,Always go through domain layer UseCases,Defeats purpose of clean architecture hard to test,Create UseCase for each business operation,https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html
|
|
8
|
-
Singleton Abuse,All,Architecture,Medium,singleton global state shared instance anti,Using singletons for everything,object AppState { var user; var cart; var settings },Use proper DI with Hilt/Koin/Swinject,Hidden dependencies hard to test race conditions,Use dependency injection framework,
|
|
9
|
-
No Dependency Injection,All,Architecture,High,no di manual instantiation tight coupling,Creating dependencies manually inside classes,class MyVM { val repo = UserRepository(ApiService()) },Use Hilt Koin Swinject or manual constructor DI,Tight coupling impossible to mock or test,Inject dependencies via constructor,https://developer.android.com/training/dependency-injection
|
|
10
|
-
Anemic Domain Model,All,Architecture,Medium,anemic domain model no logic data class,Domain models with only data no behavior,data class User(val name: String) // all logic in service,Add domain logic to models: User.isValid() User.fullName,Domain logic scattered across services,Put behavior with the data it operates on,
|
|
11
|
-
Feature Envy,All,Architecture,Medium,feature envy wrong class responsibility,Class heavily uses another class methods/data,class OrderService { fun calc(cart: Cart) = cart.items.sumOf { it.price } },Move calculation logic to Cart class,Wrong responsibility assignment tight coupling,Move method to class whose data it uses most,
|
|
12
|
-
setState Everywhere,Flutter,State,High,setstate everywhere rebuild widget state,Using setState for all state management,setState(() { _items = await api.fetchItems(); _loading = false; }),Use BLoC Cubit or Riverpod,Unnecessary rebuilds poor separation unmaintainable,Adopt proper state management solution,https://bloclibrary.dev/
|
|
13
|
-
Mutable Shared State,All,State,Critical,mutable shared state race condition thread,Sharing mutable state across threads/isolates,var sharedList = mutableListOf<Item>() // multiple coroutines,Use StateFlow/LiveData or immutable state,Race conditions crashes unpredictable behavior,Use immutable state + state management pattern,
|
|
14
|
-
Re-render Hell,React Native,State,High,rerender performance usememo usecallback memo,Unnecessary re-renders from poor state management,const App = () => { const [count setCount] = useState(0); return <ExpensiveList /> },Use React.memo useMemo useCallback properly,Jank dropped frames battery drain,Memoize expensive components and callbacks,https://react.dev/reference/react/memo
|
|
15
|
-
State in Wrong Place,All,State,Medium,state wrong scope local global misplaced,Putting local state in global store or vice versa,Redux store: { modalOpen: false buttonHover: false },Keep UI state local share only what needs sharing,Unnecessary complexity and re-renders,Local state for UI global for shared business data,
|
|
16
|
-
No Single Source of Truth,All,State,High,duplicate state sync inconsistent ssot,Same data stored in multiple places,var cachedUser in VM; var savedUser in Repo; var displayUser in UI,Single source of truth with reactive streams,Data gets out of sync inconsistent UI,Use Room/CoreData as SSOT observe with Flow/Combine,https://developer.android.com/topic/architecture/data-layer
|
|
17
|
-
Direct State Mutation,All,State,High,direct mutation state modify side effects,Modifying state objects directly,_state.items.add(newItem); notifyListeners(),_state = _state.copyWith(items: [..._state.items newItem]),Side effects lost change history broken equality,Always create new state objects via copy/copyWith,
|
|
18
|
-
Missing Error State,All,State,High,no error handling state loading empty,Not handling loading error and empty states,if (data != null) showData(data),sealed class UiState { Loading Success Error Empty },Users see blank screen on error no feedback,Use sealed class/enum for all possible UI states,
|
|
19
|
-
Storing Derived State,All,State,Medium,derived computed state redundant duplicate,Storing values that can be computed,var items; var filteredItems; var itemCount,Compute filteredItems and count from items,State sync issues stale data extra storage,Use computed properties or selectors,
|
|
20
|
-
Blocking Main Thread,All,UI,Critical,main thread ui anr freeze jank block,Doing heavy work on the main/UI thread,fun onCreate() { val data = database.queryAll() },Use coroutines/async with Dispatchers.IO,ANR dialog frozen UI dropped frames,Move heavy work to background thread/coroutine,https://developer.android.com/kotlin/coroutines
|
|
21
|
-
Hardcoded Strings,All,UI,Medium,hardcoded string i18n localization resource,Hardcoding user-facing strings in code,"Text(""Welcome back!"")",Text(stringResource(R.string.welcome_back)),Cannot localize accessibility issues,Use string resources for all user-facing text,https://developer.android.com/guide/topics/resources/string-resource
|
|
22
|
-
Hardcoded Colors,All,UI,Medium,hardcoded color hex theme design system,Using hex colors directly instead of theme,Box(modifier = Modifier.background(Color(0xFF2196F3))),Box(modifier = Modifier.background(MaterialTheme.colorScheme.primary)),No dark mode support inconsistent theming,Use theme system colors,https://developer.android.com/develop/ui/compose/designsystems/material3
|
|
23
|
-
Nested Scrolling Conflict,All,UI,High,nested scroll recyclerview scrollview conflict jank,ScrollView inside ScrollView without coordination,ScrollView { RecyclerView { } },Use NestedScrollView or single LazyColumn,Janky scroll stolen gestures broken UX,Use single scrollable container,https://developer.android.com/develop/ui/compose/lists
|
|
24
|
-
Missing Loading States,All,UI,High,no loading state blank screen async,Not showing loading indicators,if (data != null) show(data) // nothing while loading,Show skeleton/shimmer while loading,Users think app is broken,Always show loading feedback for async operations,
|
|
25
|
-
Layout Shift on Load,All,UI,Medium,layout shift cls jump content pop,Content jumping when images/data loads,Image loads and pushes text down,Reserve space with fixed aspect ratio or placeholder,Disorienting UX accidental taps,Use fixed dimensions or aspect ratio containers,
|
|
26
|
-
Ignoring Safe Area,All,UI,High,safe area notch cutout inset system bars,Content behind notch or system bars,Content goes behind status bar,Respect safe area insets on all edges,Content hidden behind system UI,Use SafeArea/safeAreaInset/WindowInsets,https://developer.android.com/develop/ui/compose/layouts/insets
|
|
27
|
-
No Image Caching,All,Performance,High,image cache memory network reload bandwidth,Loading images from network every time,Image.network(url) // no caching,CachedNetworkImage(imageUrl: url placeholder: shimmer),Wasted bandwidth slow loading,Use Coil/Glide/Kingfisher/CachedNetworkImage,
|
|
28
|
-
Memory Leak in Callback,All,Memory,Critical,memory leak callback listener retain register,Registering listeners without cleanup,onStart() { EventBus.register(this) } // never unregistered,Unregister in onStop/dispose/cleanup,Memory grows app crashes OOM,Always unregister in corresponding lifecycle method,
|
|
29
|
-
Unnecessary Recomposition,Android,Performance,High,recomposition compose unstable lambda key,Compose recomposing when it should not,LazyColumn { items(list) { Button(onClick = { doSomething(it) }) } },Use remember/derivedStateOf stable lambdas and keys,Wasted CPU jank poor battery life,Use key parameter stable lambdas Immutable annotations,https://developer.android.com/develop/ui/compose/performance
|
|
30
|
-
Large Bundle Size,React Native,Performance,Medium,bundle size hermes ram assets tree shake,App bundle too large,import _ from 'lodash' // entire library,import debounce from 'lodash/debounce',Slow download slow install,Tree-shake imports enable Hermes optimize assets,https://reactnative.dev/docs/hermes
|
|
31
|
-
No Pagination,All,Performance,High,no pagination load all memory oom list,Loading entire dataset at once,val allItems = api.getAllItems() // 10000 items,Use Paging3/pagination load 20 at a time,OOM crash slow response,Implement cursor/offset pagination,https://developer.android.com/topic/libraries/architecture/paging/v3-overview
|
|
32
|
-
Synchronous Network Call,All,Performance,Critical,synchronous network main thread block anr,Making network calls on main thread,val response = URL(apiUrl).readText() // blocks,withContext(Dispatchers.IO) { api.fetch() },ANR frozen UI app killed by system,Always use async/await coroutines or callbacks,https://developer.android.com/kotlin/coroutines
|
|
33
|
-
Widget Rebuild Storm,Flutter,Performance,High,widget rebuild unnecessary build frequent,Entire widget tree rebuilding on minor change,setState(() { _title = newTitle; }) // rebuilds everything,Use BLoC/Consumer/Selector to scope rebuilds,Poor performance janky scrolling,Scope rebuilds to affected widgets only,https://docs.flutter.dev/perf/best-practices
|
|
34
|
-
Not Handling Lifecycle,Android,Lifecycle,Critical,lifecycle activity fragment destroy recreate rotation,Not handling config changes and lifecycle,Store data in Activity fields lost on rotation,Use ViewModel to survive configuration changes,Data loss on rotation crash on backgrounding,Use ViewModel + SavedStateHandle,https://developer.android.com/topic/libraries/architecture/viewmodel
|
|
35
|
-
Retain Cycle,iOS,Memory,Critical,retain cycle strong reference memory leak arc closure,Strong reference cycle between objects,closure = { self.doWork() } // strong capture,Use [weak self] or [unowned self] in closures,Memory never freed app memory grows,Use [weak self] in closures that capture self,https://docs.swift.org/swift-book/documentation/the-swift-programming-language/automaticreferencecounting/
|
|
36
|
-
Not Disposing Controllers,Flutter,Lifecycle,High,dispose controller textediting animation scroll leak,Not calling dispose on controllers,final ctrl = TextEditingController(); // no dispose,@override void dispose() { ctrl.dispose(); super.dispose(); },Memory leak resource leak potential crashes,Override dispose() clean up all controllers,https://api.flutter.dev/flutter/widgets/State/dispose.html
|
|
37
|
-
Missing Cleanup in useEffect,React Native,Lifecycle,High,useeffect cleanup subscription listener return,useEffect without cleanup function,useEffect(() => { socket.connect(); }),useEffect(() => { socket.connect(); return () => socket.disconnect(); }),Memory leak zombie listeners stale callbacks,Always return cleanup function from useEffect,https://react.dev/reference/react/useEffect
|
|
38
|
-
Ignoring App Lifecycle,All,Lifecycle,Medium,background foreground app lifecycle pause resume,Not handling app going to background/foreground,Keep timers and connections running in background,Pause work on background resume on foreground,Battery drain wasted resources,Use LifecycleObserver/AppDelegate/WidgetsBindingObserver,https://developer.android.com/guide/components/activities/activity-lifecycle
|
|
39
|
-
Deep Nesting Navigation,All,Navigation,Medium,deep nesting navigation back stack levels,Deeply nested navigation stacks 6+ levels,Screen A -> B -> C -> D -> E -> F,Use flat navigation with tabs max 3-4 levels,Confusing UX user gets lost,Flatten navigation use tabs or modal for side flows,
|
|
40
|
-
No Deep Link Support,All,Navigation,Medium,deep link universal link app link url,App has no deep linking support,Only navigate via taps inside the app,Support deep links for all major screens,Cannot share content poor marketing,Implement deep linking from the start,https://developer.android.com/training/app-links
|
|
41
|
-
Losing Navigation State,All,Navigation,High,navigation state lost backstack destroy death,Navigation state lost on process death,Navigate back and screens are blank,Save and restore navigation state,Users lose their place,Use SavedStateHandle/StateRestoration,https://developer.android.com/topic/libraries/architecture/saving-states
|
|
42
|
-
Hard-coded Routes,All,Navigation,Medium,hardcoded route string navigation typo,Using raw strings for navigation routes,navigator.push('/home/profile/123'),Use typed routes or route constants with type safety,Typo-prone no compile-time safety,Use type-safe navigation,https://developer.android.com/guide/navigation/design/type-safety
|
|
43
|
-
No Back Handler,Android,Navigation,High,back handler predictive back gesture exit,Not handling system back properly,System back closes app from any screen,Use BackHandler or predictive back API,Users accidentally exit app,Handle back press with confirmation,https://developer.android.com/
|
|
44
|
-
No Offline Support,All,Network,Medium,offline cache first network connection,App completely unusable without network,if (!isConnected) showError('No internet'),Cache data locally show cached + sync online,Unusable on poor connection,Implement offline-first with local cache,
|
|
45
|
-
No Request Retry,All,Network,Medium,retry exponential backoff network failure,No retry logic for failed requests,val response = api.getData() // fails once gives up,Implement exponential backoff retry max 3 attempts,Transient failures shown as errors,Add retry with exponential backoff,
|
|
46
|
-
Ignoring HTTP Errors,All,Network,High,http error status code ignore 4xx 5xx,Not handling non-200 HTTP status codes,val data = response.body() // assumes always 200,Check status code handle 4xx and 5xx properly,Silent failures corrupted data,Handle all HTTP status codes,
|
|
47
|
-
No Request Cancellation,All,Network,Medium,cancel request dispose viewmodel navigate away,Not cancelling requests when leaving screen,API calls continue after user navigates away,Cancel requests in onCleared/dispose/cleanup,Wasted resources updating destroyed UI,Tie request lifecycle to screen lifecycle,
|
|
48
|
-
Trusting Server Data,All,Network,High,trust server validation input sanitize null,Blindly trusting all data from server,val name = response.name!!; textView.text = name,Validate and sanitize all server responses,Crashes on null/malformed data,Validate all fields handle missing data,
|
|
49
|
-
No Unit Tests,All,Testing,High,no tests unit test coverage regression,No automated tests in the project,Ship code without any tests,Write unit tests for ViewModels repositories logic,Regression bugs fear of refactoring,Start with ViewModel/BLoC tests then expand,https://developer.android.com/training/testing
|
|
50
|
-
Hardcoded API Keys,All,Security,Critical,api key hardcoded secret exposed source,API keys committed to source code,const val API_KEY = 'sk-abc123...',Use BuildConfig/xcconfig/env vars and .gitignore,Keys exposed in decompiled APK/IPA,Store in local.properties/xcconfig never commit,https://owasp.org/www-project-mobile-top-10/
|
|
51
|
-
No SSL Pinning,All,Security,High,ssl pinning certificate mitm attack,No certificate pinning for API calls,OkHttpClient() // trusts any valid cert,Implement certificate/public key pinning,Man-in-the-middle attacks,Pin server certificate or public key,https://developer.android.com/privacy-and-security/security-config#CertificatePinning
|
|
52
|
-
Storing Sensitive in Prefs,All,Security,Critical,sharedpreferences userdefaults plaintext sensitive token,Storing tokens/passwords in plain preferences,SharedPreferences.putString('token' jwt),Use EncryptedSharedPreferences/Keychain/flutter_secure_storage,Tokens readable by rooted device,Use platform secure storage,https://developer.android.com/reference/androidx/security/crypto/EncryptedSharedPreferences
|
|
53
|
-
No Input Validation,All,Security,High,input validation xss injection sanitize,Not validating user input,textView.text = userInput // direct usage,Validate sanitize and escape all user inputs,XSS injection SQL injection crashes,Validate format length content of all inputs,
|
|
54
|
-
No ProGuard R8,Android,Security,Medium,proguard r8 obfuscation minify shrink,Not enabling code shrinking,minifyEnabled false // in build.gradle,minifyEnabled true with proper proguard-rules.pro,Larger APK reverse engineering easy,Enable R8 with proper keep rules,https://developer.android.com/build/shrink-code
|
|
55
|
-
Logging Sensitive Data,All,Security,High,log sensitive password token pii debug production,Logging passwords tokens or PII,Log.d(TAG 'User token: $token'),Never log sensitive data use redaction in production,Credentials leaked via logs,Strip debug logs in release configure log levels,
|
|
56
|
-
Composable Side Effects,Android,Compose,Critical,compose side effect launched disposable remember coroutine,Running side effects directly in composable body without LaunchedEffect,@Composable fun Screen() { api.fetchData() // runs on every recomposition },@Composable fun Screen() { LaunchedEffect(Unit) { api.fetchData() } },Runs on every recomposition; infinite network calls; crashes,Use LaunchedEffect DisposableEffect or rememberCoroutineScope,https://developer.android.com/develop/ui/compose/side-effects
|
|
57
|
-
State Hoisting Failure,Android,Compose,High,compose state hoisting remember mutablestateof local,Keeping state local in child composable instead of hoisting to parent,@Composable fun Search() { var query by remember { mutableStateOf('') } },@Composable fun Search(query: String onQueryChange: (String) -> Unit),Parent cannot observe or control child state; breaks unidirectional flow,Hoist state to lowest common ancestor; pass state down events up,https://developer.android.com/develop/ui/compose/state#state-hoisting
|
|
58
|
-
Remember with Wrong Key,Android,Compose,High,compose remember key recomposition stale cache invalidate,Using remember without keys causing stale cached values,val data = remember { expensiveCompute(input) } // stale when input changes,val data = remember(input) { expensiveCompute(input) } // recomputes on change,Cached value never updates when inputs change; shows stale data,Pass keys to remember that trigger recomputation,https://developer.android.com/develop/ui/compose/side-effects#remember
|
|
59
|
-
derivedStateOf Misuse,Android,Compose,Medium,compose derivedstateof unnecessary overhead recomposition filter,Using derivedStateOf for values that change with every state change,val text = remember { derivedStateOf { input.value } } // unnecessary,val filteredList = remember { derivedStateOf { list.filter { it.isActive } } },derivedStateOf adds overhead; only useful when result changes less often than input,Use derivedStateOf only when output changes less frequently than input,https://developer.android.com/develop/ui/compose/side-effects#derivedstateof
|
|
60
|
-
Unstable Lambda in Compose,Android,Compose,High,compose lambda recomposition unstable capture remember callback,Passing unstable lambdas causing unnecessary recompositions,LazyColumn { items(list) { Button(onClick = { viewModel.select(it) }) } },val onSelect = remember { { item: Item -> viewModel.select(item) } },Unstable lambda prevents skipping recomposition of items; janky scrolling,Use remember for lambdas or enable Strong Skipping Mode,https://developer.android.com/develop/ui/compose/performance/stability
|
|
61
|
-
GlobalScope Coroutine,Android,Coroutine,Critical,globalscope coroutine launch leak lifecycle cancel fire forget,Using GlobalScope instead of viewModelScope or lifecycleScope,GlobalScope.launch { api.fetchData() },viewModelScope.launch { api.fetchData() },Never cancelled; outlives component; memory leak; ignores lifecycle,Use viewModelScope lifecycleScope or custom CoroutineScope,https://developer.android.com/kotlin/coroutines/coroutines-best-practices
|
|
62
|
-
runBlocking on Main,Android,Coroutine,Critical,runblocking main thread anr block coroutine bridge,Using runBlocking on Main thread to bridge sync and async code,fun getData() = runBlocking { api.fetch() } // blocks main thread,suspend fun getData() = api.fetch() // or use viewModelScope.launch,ANR after 5 seconds; frozen UI; app killed by system,Never use runBlocking on main; use suspend functions or launch,https://developer.android.com/kotlin/coroutines/coroutines-best-practices
|
|
63
|
-
Collecting Flow in ViewModel init,Android,Coroutine,High,flow collect init viewmodel launch stateflow repeatonlifecycle,Collecting Flow in ViewModel init without proper scoping,init { viewModelScope.launch { repo.data.collect { _state.value = it } } },val state = repo.data.stateIn(viewModelScope SharingStarted.WhileSubscribed(5000) initial),Flow collected even when UI not visible; wasted resources,Use stateIn with WhileSubscribed for lifecycle-aware collection,https://developer.android.com/kotlin/flow/stateflow-and-sharedflow
|
|
64
|
-
Not Using repeatOnLifecycle,Android,Lifecycle,High,repeatonlifecycle flow collect lifecycle started activity fragment,Collecting Flow in Activity/Fragment without lifecycle awareness,lifecycleScope.launch { viewModel.state.collect { updateUI(it) } },lifecycleScope.launch { repeatOnLifecycle(STARTED) { viewModel.state.collect { updateUI(it) } } },Collects in background wasting resources; potential crashes on destroyed views,Use repeatOnLifecycle or collectAsStateWithLifecycle in Compose,https://developer.android.com/topic/libraries/architecture/coroutines#lifecycle-aware
|
|
65
|
-
ViewModel Factory Boilerplate,Android,Architecture,Medium,viewmodel factory provider deprecated assistedinject creationextras,Writing manual ViewModel factory instead of using Hilt or CreationExtras,class MyVMFactory(val repo: Repo) : ViewModelProvider.Factory { override fun <T> create() },@HiltViewModel class MyVM @Inject constructor(val repo: Repo) : ViewModel(),Unnecessary boilerplate; error-prone; manual dependency wiring,Use @HiltViewModel or CreationExtras (AGP 2.5+),https://developer.android.com/training/dependency-injection/hilt-android
|
|
66
|
-
Hilt Missing EntryPoint,Android,DI,High,hilt entrypoint inject contentprovider broadcastreceiver workmanager,Not using @EntryPoint for non-standard Hilt injection targets,class MyReceiver : BroadcastReceiver() { val repo = UserRepository() // manual },@AndroidEntryPoint class MyReceiver : BroadcastReceiver() @Inject lateinit var repo: Repo,Manual instantiation; missing initialization; test-unfriendly,Use @EntryPoint for WorkManager ContentProvider BroadcastReceiver,https://developer.android.com/training/dependency-injection/hilt-android#not-supported
|
|
67
|
-
Exposing MutableStateFlow,Android,State,High,mutablestateflow expose public private backing field viewmodel,Exposing MutableStateFlow publicly from ViewModel,val state = MutableStateFlow(Initial) // public mutable,private val _state = MutableStateFlow(Initial); val state: StateFlow<X> = _state.asStateFlow(),Views can modify ViewModel state directly; breaks UDF,Use private MutableStateFlow with public StateFlow accessor,https://developer.android.com/kotlin/flow/stateflow-and-sharedflow
|
|
68
|
-
SwiftUI Body Heavy Computation,iOS,SwiftUI,High,swiftui body computed property heavy performance view,Doing expensive work in SwiftUI body property,var body: some View { let filtered = items.filter { expensive($0) }; List(filtered) },@State private var filtered = []; func updateFilter() { filtered = items.filter { } },Body runs on every re-render; expensive filter runs repeatedly,Compute in onChange or task; cache results in @State,https://developer.apple.com/documentation/swiftui
|
|
69
|
-
ObservableObject Over-Publishing,iOS,SwiftUI,High,observableobject published objectwillchange unnecessary rerender,Too many @Published properties causing unnecessary view updates,class VM: ObservableObject { @Published var a; @Published var b; @Published var c },Use @Observable macro (iOS 17+) for granular tracking,Every @Published change triggers all observing views to re-render,Use @Observable or split into multiple ObservableObjects,https://developer.apple.com/documentation/observation/observable()
|
|
70
|
-
Force Unwrapping Optionals,iOS,Swift,Critical,force unwrap optional bang crash nil unexpected,Using ! to force unwrap optionals that might be nil,let name = user.name! // crashes if nil,guard let name = user.name else { return },Runtime crash if value is nil; common source of production crashes,Use guard let if let or ?? with defaults,https://docs.swift.org/swift-book/documentation/the-swift-programming-language/optionalchaining/
|
|
71
|
-
setState with API Call,Flutter,State,High,setstate api call network widget build futurebuilder,Calling API directly in widget with setState for result,setState(() { data = await api.fetch(); }) // in initState,Use BLoC/Riverpod/FutureBuilder for async data,Mixed concerns; can't test; race conditions on rapid rebuilds,Separate data fetching from UI using state management,https://docs.flutter.dev/data-and-backend/state-mgmt/options
|
|
72
|
-
BuildContext Across Async Gap,Flutter,Architecture,Critical,buildcontext async gap mounted scaffold navigator context,Using BuildContext after await when widget might be unmounted,await api.fetch(); ScaffoldMessenger.of(context).showSnackBar(snack),if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar(snack),Widget may be unmounted; context invalid; crash or wrong behavior,Check mounted before using context after await,https://dart.dev/tools/linter-rules/use_build_context_synchronously
|
|
73
|
-
Provider Without Select,Flutter,Performance,Medium,provider select watch read consumer unnecessary rebuild,Using context.watch when only one field needed causing full rebuilds,final state = context.watch<AppState>(); // rebuilds on any change,final name = context.select<AppState String>((s) => s.name);,Entire widget rebuilds when any AppState field changes,Use select to pick specific fields; minimizes rebuilds,https://pub.dev/packages/provider
|
|
74
|
-
Inline Styles in RN,React Native,UI,Medium,inline style stylesheet create performance object allocation,Creating style objects inline in render causing re-allocation,<View style={{flex: 1 backgroundColor: 'red'}} />,<View style={styles.container} />; const styles = StyleSheet.create({container: {flex: 1}}),New object allocated every render; breaks PureComponent memo,Use StyleSheet.create outside component,https://reactnative.dev/docs/stylesheet
|
|
75
|
-
Console.log in Production,React Native,Performance,Medium,console log production performance bridge debug remove strip,Leaving console.log statements in production build,console.log('user data:' JSON.stringify(userObject)),if (__DEV__) console.log('debug info'); // or use babel-plugin-transform-remove-console,Serialization overhead; sensitive data exposure; bridge congestion,Use babel plugin to strip console in production,https://reactnative.dev/docs/performance
|
|
76
|
-
Uncontrolled re-renders in List,React Native,Performance,High,flatlist rerender key extractor item separator optimization,FlatList items re-rendering on every state change,<FlatList data={items} renderItem={({item}) => <Item data={item} store={entireStore} />} />,<FlatList data={items} renderItem={renderItem} keyExtractor={keyExtractor} getItemLayout={getItemLayout} />,Entire list re-renders; dropped frames; janky scrolling,Use React.memo keyExtractor getItemLayout; minimize item props,https://reactnative.dev/docs/flatlist
|
|
77
|
-
Async Storage for Sensitive Data,React Native,Security,Critical,asyncstorage sensitive token password plaintext unencrypted,Storing tokens or passwords in AsyncStorage (unencrypted),await AsyncStorage.setItem('token' jwtToken),await Keychain.setGenericPassword('user' token {service: 'auth'}),AsyncStorage is plaintext; readable on rooted devices,Use react-native-keychain for sensitive data,https://github.com/oblador/react-native-keychain
|
|
78
|
-
Platform Channel in Hot Path,Flutter,Performance,High,platform channel method invocation hot path loop frequent native,Calling platform channels in loops or animations,for (item in items) { await methodChannel.invokeMethod('process' item); },final results = await methodChannel.invokeMethod('processBatch' items);,Each call has ~0.5ms overhead; 100 calls = 50ms; jank during animation,Batch platform channel calls; use Pigeon for type-safe interface,https://docs.flutter.dev/platform-integration/platform-channels
|
|
79
|
-
No Error Boundary,React Native,Architecture,High,error boundary crash fallback react native component tree,No error boundaries causing entire app crash on JS error,// No ErrorBoundary; one component crash takes down entire app,class ErrorBoundary extends React.Component { static getDerivedStateFromError(e) { return {hasError: true} } },Single component error crashes entire React tree,Wrap screen-level and critical components in ErrorBoundary,https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary
|
|
80
|
-
Magic Numbers,All,Code Quality,Medium,magic number constant named value meaning readability,Using unexplained numeric literals in code,if (retryCount > 3) { delay(2000) },if (retryCount > MAX_RETRIES) { delay(RETRY_DELAY_MS) },Unclear intent; hard to change; scattered duplicate values,Extract to named constants with descriptive names,
|
|
81
|
-
Magic Numbers,All,Clean Code,Medium,magic number constant named hardcoded value readability,Hardcoded numeric values with no explanation scattered through code,if (retryCount > 3) { delay(5000) },companion object { const val MAX_RETRIES = 3; const val RETRY_DELAY_MS = 5000L }; if (retryCount > MAX_RETRIES) delay(RETRY_DELAY_MS),Unreadable; changing value requires finding all instances; no context for why 3 or 5000,Extract to named constants with meaningful names,https://developer.android.com/kotlin/style-guide
|
|
82
|
-
God ViewModel,Android,Clean Code,Critical,god viewmodel massive 1000 lines srp single responsibility bloated,ViewModel handling 10+ responsibilities: auth + navigation + analytics + UI state + validation + caching,class CheckoutViewModel { fun processPayment(); fun validateCard(); fun applyDiscount(); fun updateCart(); fun loadAddress(); fun trackEvent(); fun refreshUser() },Split: CartViewModel + PaymentViewModel + AddressViewModel; Use UseCases for business logic,Untestable; impossible to reason about; merge conflict magnet; 1500+ lines,Extract UseCases; split by screen/feature; ViewModel orchestrates not implements,https://developer.android.com/topic/architecture/ui-layer
|
|
83
|
-
Primitive Obsession,All,Clean Code,Medium,primitive obsession string int type safety wrapper value class,Using raw String/Int where domain types provide safety,fun processOrder(orderId: String customerId: String productId: String amount: Int),@JvmInline value class OrderId(val value: String); @JvmInline value class CustomerId(val value: String); fun processOrder(orderId: OrderId customerId: CustomerId),Easy to swap orderId and customerId accidentally; no compile-time safety; bugs at runtime,Use Kotlin value classes or typealiases for domain primitives,https://kotlinlang.org/docs/inline-classes.html
|
|
84
|
-
Callback Hell,All,Clean Code,High,callback hell nested pyramid async completion handler indentation,Deeply nested callbacks making code unreadable and error-prone,api.login { user -> api.getProfile(user.id) { profile -> api.getOrders(profile.id) { orders -> updateUI(orders) } } },val user = api.login(); val profile = api.getProfile(user.id); val orders = api.getOrders(profile.id); updateUI(orders) // suspend functions,Pyramid of doom; error handling at each level; impossible to follow flow; can't cancel,Use suspend functions (Kotlin); async/await (Swift/JS); or Flow/Combine,https://developer.android.com/kotlin/coroutines
|
|
85
|
-
Stringly Typed APIs,All,Clean Code,Medium,string typed enum sealed navigation route key preference magic string,Using raw strings as identifiers instead of enums or sealed types,"navController.navigate(""detail/123""); prefs.getString(""theme""); when (status) { ""loading"" -> ...","@Serializable data class DetailRoute(val id: String); navController.navigate(DetailRoute(""123"")); enum class Theme { LIGHT DARK }",Typos cause runtime crashes; no refactoring safety; no exhaustive when; find-and-replace breaks,Use enums sealed interfaces or @Serializable data classes for type safety,https://developer.android.com/guide/navigation/design/type-safety
|
|
86
|
-
Long Parameter List,All,Clean Code,Medium,long parameter list function arguments config builder data class,Functions with 5+ parameters; hard to remember order; easy to swap arguments,fun createUser(name: String email: String age: Int city: String country: String bio: String avatar: String premium: Boolean),data class CreateUserRequest(val name: String val email: String val age: Int val city: String); fun createUser(request: CreateUserRequest),Arguments easily swapped; hard to read at call site; adding new param requires changing all callers,Group into data class or builder pattern; use named arguments in Kotlin,https://developer.android.com/kotlin/style-guide
|
|
87
|
-
Feature Envy,All,Clean Code,Medium,feature envy method class responsibility data access encapsulation,Method that uses more data from another class than its own,fun OrderViewModel.calculateTotal() { val items = cart.items; val tax = cart.taxRate; val discount = cart.discount; return items.sumOf { it.price } * (1 + tax) - discount },fun Cart.calculateTotal(): Double { return items.sumOf { it.price } * (1 + taxRate) - discount }; // Method belongs in Cart,Breaks encapsulation; changes to Cart internals require ViewModel changes; tight coupling,Move method to the class whose data it primarily uses,
|
|
88
|
-
No Error Handling Strategy,All,Maintainability,Critical,error handling strategy result either sealed exception crash production,Inconsistent error handling; mix of try-catch exceptions Result and nullable returns,fun getUser(): User = api.getUser() // Throws; fun getOrders(): List<Order>? // Nullable; fun getCart(): Result<Cart> // Result,Consistent: suspend fun getUser(): Result<User>; // Always Result; ViewModel handles fold(onSuccess onFailure),Unpredictable API surface; callers don't know what to expect; crashes in production,Adopt consistent strategy: Result<T> or sealed class or Arrow Either across entire codebase,https://developer.android.com/kotlin/coroutines/coroutines-best-practices
|
|
89
|
-
Tight Coupling to Framework,All,Maintainability,High,tight coupling framework dependency inversion testability android context,Business logic directly depending on Android framework classes,class UserRepository(private val context: Context) { fun save(user: User) { context.getSharedPreferences(...).edit().putString(user.json).apply() } },interface UserStorage { suspend fun save(user: User) }; class SharedPrefUserStorage(context: Context) : UserStorage; class UserRepository(private val storage: UserStorage),Can't unit test without Android; business logic untestable; migration impossible,Dependency inversion: depend on interfaces not implementations,https://developer.android.com/training/dependency-injection
|
|
90
|
-
Missing Mapper Layer,All,Maintainability,High,mapper dto entity domain model separation layer boundary clean,Domain models directly using API DTOs or database entities; tightly coupled,"@Entity data class User(@PrimaryKey val id: String @Json(name = ""first_name"") val firstName: String) // Used everywhere",Separate: UserDto (API) + UserEntity (DB) + User (domain); fun UserDto.toDomain() fun User.toEntity(),API change breaks UI; database schema change requires UI update; no boundary isolation,Create mapper functions at layer boundaries; domain model is source of truth,https://developer.android.com/topic/architecture/data-layer
|
|
91
|
-
No Logging Strategy,All,Maintainability,Medium,logging strategy timber debug release production strip sanitize,Inconsistent logging; Log.d everywhere; sensitive data in production logs,"Log.d(""TAG"" ""User password: $password""); Log.d(""TAG"" ""Token: $token"")","Timber.d(""Login attempt for %s"" username); // Stripped in release; no sensitive data; structured",Sensitive data leaked in production logs; inconsistent tags; no way to strip debug logs,Use Timber; configure release tree; strip debug logs with R8; never log PII,https://github.com/JakeWharton/timber
|
|
92
|
-
Hardcoded Strings in UI,All,Maintainability,Medium,hardcoded string ui localization i18n l10n translation resource,Hardcoded UI strings making localization impossible,"Text(""Welcome back!""); Button(""Submit Order"")","Text(stringResource(R.string.welcome_back)); // or LocalizedStringKey(""welcome_back"") in SwiftUI",Can't translate app; changing copy requires code change and redeploy; no RTL support,Extract all user-visible strings to resources; use string formatting for dynamic content,https://developer.android.com/guide/topics/resources/localization
|
|
93
|
-
Ignoring Code Formatting,All,Maintainability,Low,code formatting ktfmt ktlint spotless detekt lint consistent style,Inconsistent code formatting; tabs vs spaces; brace style wars; messy PRs,Mixed formatting: some files use 2-space indent others 4-space; trailing whitespace; no linting,"// build.gradle.kts: plugins { id(""com.diffplug.spotless"") }; spotless { kotlin { ktfmt().googleStyle() } }; // Enforced in CI",Noisy diffs; style debates in PRs; inconsistent codebase appearance,Configure ktfmt/ktlint with Spotless plugin; enforce in CI pre-commit hook,https://developer.android.com/kotlin/style-guide
|
|
94
|
-
No Dependency Injection,All,Scalability,Critical,dependency injection di hilt koin manual creation testability coupling,Manually creating dependencies everywhere; tight coupling; untestable,class UserViewModel { val repo = UserRepository(ApiClient() AppDatabase.getInstance().userDao()) },@HiltViewModel class UserViewModel @Inject constructor(private val repo: UserRepository) : ViewModel(),Can't substitute test doubles; changing dependency requires modifying every consumer; circular deps,Use Hilt (Android) or Koin; constructor injection; interface bindings,https://developer.android.com/training/dependency-injection/hilt-android
|
|
95
|
-
Shared Mutable State,All,Scalability,Critical,shared mutable state global singleton concurrency race condition thread safety,Global mutable state accessed from multiple threads without synchronization,object AppState { var currentUser: User? = null; var cartItems = mutableListOf<Item>() }; // Modified from any thread,private val _user = MutableStateFlow<User?>(null); val user: StateFlow<User?> = _user.asStateFlow() // Thread-safe; single writer,Race conditions; data corruption; impossible to reproduce bugs; crashes under load,Use StateFlow/LiveData for reactive state; Mutex for critical sections; immutable data classes,https://developer.android.com/kotlin/flow/stateflow-and-sharedflow
|
|
96
|
-
Monolithic Navigation,All,Scalability,High,monolithic navigation graph single navgraph nested module scale route,Single navigation graph with all 50+ screens; merge conflicts; can't modularize,"NavHost { composable(""home"") { }; composable(""search"") { }; composable(""profile"") { }; ... 50 more routes in one file }",// Each feature module exposes navigation: fun NavGraphBuilder.homeGraph() { composable<HomeRoute> { HomeScreen() } }; // Root: NavHost { homeGraph(); searchGraph(); profileGraph() },Monolithic file; every team edits same navigation; can't parallelize feature development,Nested nav graphs per feature module; each module owns its routes,https://developer.android.com/guide/navigation/design/nested-graphs
|
|
97
|
-
No Tests,All,Testing,Critical,no test coverage untested unit integration ship pray,Shipping code with zero automated tests,func updatePrice(newPrice: Decimal) { product.price = newPrice; notifyObservers() } // No tests anywhere,@Test fun updatePrice_updatesValue() { viewModel.updatePrice(9.99); assertEquals(9.99 viewModel.product.value.price) },One bug fix breaks 3 other features; regression on every release; fear of refactoring,Write tests for critical business logic first; aim for 80%+ coverage on domain layer,https://developer.android.com/training/testing
|
|
98
|
-
Testing Implementation Details,All,Testing,High,test implementation detail brittle fragile mock verify internal,Tests that verify HOW code works instead of WHAT it does; break on refactor,verify(exactly = 1) { repo.save(any()) }; // Tests internal call; breaks if implementation changes,val result = viewModel.submitOrder(order); assertEquals(OrderStatus.CONFIRMED result.status) // Tests behavior,Tests break on every refactor even when behavior unchanged; zero confidence; test maintenance hell,Test public behavior and outputs; don't verify internal method calls unless side-effect is the contract,https://testing.googleblog.com/2013/08/testing-on-toilet-test-behavior-not.html
|
|
99
|
-
Flaky Tests in CI,All,Testing,High,flaky test intermittent fail pass ci unreliable timing race condition,Tests that randomly pass/fail; team starts ignoring CI results,@Test fun testNetworkCall() { Thread.sleep(5000); assertTrue(result.isSuccess) } // Timing dependent,@Test fun testNetworkCall() = runTest { val result = fakeRepo.getData(); assertTrue(result.isSuccess) } // Deterministic,Team ignores CI failures; broken code merges; flaky tests erode trust in entire test suite,Use fakes instead of mocks; use TestCoroutineDispatcher; avoid Thread.sleep; deterministic tests,https://developer.android.com/training/testing/fundamentals
|
|
100
|
-
No Single Source of Truth,All,Data,Critical,single source truth ssot cache api database stale inconsistent duplicated,Same data stored in multiple places; becomes inconsistent,var cachedUser: User? = null; fun getUser(): User { cachedUser = api.getUser(); return cachedUser!! } // Also in Room; also in ViewModel,fun getUser(): Flow<User> = userDao.observe().onStart { refreshFromNetwork() } // Room is SSOT,Stale data shown; user sees different info on different screens; cache invalidation bugs,Make local database (Room) single source of truth; network refreshes database; UI observes database,https://developer.android.com/topic/architecture/data-layer#source-of-truth
|
|
101
|
-
Repository Returns Entity,All,Data,Medium,repository room entity dto leak domain layer boundary separation,Repository exposing Room entities or API DTOs directly to ViewModel/UI,fun getUsers(): Flow<List<UserEntity>> // Room entity with @ColumnInfo annotations leaked to UI,fun getUsers(): Flow<List<User>> // Clean domain model; mapped in repository; UI decoupled from DB schema,Database schema change forces UI update; API response change ripples through entire app,Map Entity → Domain model in repository; UI never sees database annotations or API field names,https://developer.android.com/topic/architecture/data-layer
|
|
102
|
-
Fire and Forget Coroutine,Android,Coroutine,High,fire forget coroutine launch exception lost crash silent scope,Launching coroutine without handling exceptions; silent failures,viewModelScope.launch { api.saveData(data) } // Exception silently swallowed by default handler,viewModelScope.launch { runCatching { api.saveData(data) }.onFailure { _error.emit(it.message) } } // Error handled and shown,Errors silently swallowed; data loss; user thinks action succeeded but it failed,Always handle exceptions in coroutines; use CoroutineExceptionHandler or runCatching,https://developer.android.com/kotlin/coroutines/coroutines-best-practices
|
|
103
|
-
Collecting Flow in Wrong Scope,Android,Coroutine,High,flow collect lifecycle repeatonlifecycle started launchwhenstrated leak,Collecting Flow in onCreate without lifecycle awareness; processes events when app backgrounded,lifecycleScope.launch { flow.collect { updateUI(it) } } // Collects even in background; wasted resources,lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { flow.collect { updateUI(it) } } },Processes events in background; battery drain; potential crashes updating invisible UI,Use repeatOnLifecycle(STARTED) or collectAsStateWithLifecycle() in Compose,https://developer.android.com/kotlin/flow/stateflow-and-sharedflow
|
|
104
|
-
Business Logic in UI,All,Architecture,Critical,business logic ui composable view activity fragment viewmodel separation,Business logic (validation calculation) directly in Composable/View,@Composable fun Checkout() { val total = items.sumOf { it.price * it.qty } * (1 - discount); if (total > 100) freeShipping = true },@Composable fun Checkout(viewModel: CheckoutViewModel) { val state by viewModel.state.collectAsStateWithLifecycle(); TotalText(state.formattedTotal) },Untestable; duplicated logic across platforms; UI test required for business rule verification,Extract all business logic to ViewModel or UseCase; UI only renders state,https://developer.android.com/topic/architecture/ui-layer
|
|
105
|
-
Exposing MutableState,Android,State,High,expose mutablestateflow mutablelivedata encapsulation internal state viewmodel,ViewModel exposing MutableStateFlow/MutableLiveData to UI; breaking encapsulation,val state = MutableStateFlow(UiState()) // UI can mutate ViewModel state directly,private val _state = MutableStateFlow(UiState()); val state: StateFlow<UiState> = _state.asStateFlow(),UI can modify ViewModel state bypassing business logic; unintended state mutations; untraceable bugs,Expose read-only StateFlow; keep MutableStateFlow private; mutate only through ViewModel functions,https://developer.android.com/kotlin/flow/stateflow-and-sharedflow
|
|
106
|
-
buildSrc Slowing Builds,Android,Build,Medium,buildsrc build logic slow invalidation convention plugin composite,Using buildSrc which invalidates all build caches on any change,// buildSrc/build.gradle.kts: any tiny change invalidates ENTIRE project cache,// build-logic/convention module: changes only invalidate convention plugin consumers; 80% faster incremental,buildSrc change = full project rebuild; no incremental; 5min rebuild from scratch,Move build logic to included build (build-logic) with composite builds,https://developer.android.com/build/migrate-to-catalogs
|
|
107
|
-
Unused Dependencies,All,Build,Medium,unused dependency dead code classpath bloat size apk ipa bundle,Dependencies added but never used; bloating app size and build time,// 50 dependencies; 20 unused; +8MB APK size; +30s build time; security surface increased,// ./gradlew buildHealth; // Identifies unused declared and used-undeclared dependencies,Add libraries 'just in case'; never remove; 50 deps but only 30 used,Zero unused dependencies,https://github.com/autonomousapps/dependency-analysis-android-gradle-plugin
|
|
108
|
-
No Loading Feedback,All,UX,High,loading feedback indicator spinner skeleton progress perceived performance,No loading indicator; user thinks app is frozen or broken,"// Button(onClick = { api.submit() }) { Text(""Post"") } // No loading state; user taps 5 times; 5 submissions","PostButton(onClick = { isLoading = true; viewModel.submit() } enabled = !isLoading) { if (isLoading) CircularProgressIndicator() else Text(""Post"") }",Blank screen during network call; no visual feedback; user taps button multiple times,Instant loading feedback,
|
|
109
|
-
Destructive Action Without Confirmation,All,UX,Medium,destructive action confirmation delete dialog undo irreversible,Delete/irreversible actions with no confirmation; accidental data loss,// IconButton(onClick = { dao.delete(item) }) // Immediately deletes; no confirmation; no undo; data lost,"AlertDialog(title = { Text(""Delete this item?"") } confirmButton = { TextButton(onClick = { delete() }) { Text(""Delete"" color = MaterialTheme.colorScheme.error) } })",Swipe-to-delete with no confirmation; tap 'Delete Account' instantly deletes,Confirm before destructive actions,
|
|
110
|
-
Ignoring Keyboard,All,UX,Medium,keyboard ime soft input adjustment scroll overlap textfield focus,Keyboard overlapping input fields; form fields hidden behind keyboard,// TextField behind keyboard; user types blind; can't see input or errors,// Scaffold(modifier = Modifier.imePadding()); // Or: BringIntoViewRequester for focused field,Form field hidden behind keyboard; user can't see what they're typing,Fields visible above keyboard,https://developer.android.com/develop/ui/compose/layouts/insets
|
|
111
|
-
Large SwiftUI View Body,iOS,SwiftUI,High,swiftui body large refactor extract subview performance,View body with 200+ lines; impossible to understand and slow to compile,// var body: some View { VStack { /* 400 lines of nested HStack VStack Group ForEach if-else */ } } // Unreadable; slow compile,struct OrderScreen: View { var body: some View { VStack { HeaderSection(); ItemsList(); TotalSection(); CheckoutButton() } } } // 4 lines,500-line body with nested conditionals; 30s build time for one file,< 30 lines per body,
|
|
112
|
-
Not Using @MainActor,iOS,Swift,Medium,mainactor swift concurrency sendable actor isolation ui thread,Updating UI from background thread causing crashes in Swift 6,// class ViewModel: ObservableObject { @Published var items: [Item] = []; func load() { Task { items = await api.fetch() } } } // Off-main update,@MainActor class HomeViewModel: ObservableObject { @Published var items: [Item] = []; func load() async { items = try await api.fetch() } },Update @Published properties from background thread; crash in Swift 6 strict concurrency,@MainActor for UI code,https://developer.apple.com/documentation/swift/mainactor
|
|
113
|
-
Not Using Keys in Lists,Flutter,Performance,Medium,flutter key widget list rebuild globalkey valuekey uniquekey identity,Missing keys in dynamic lists; incorrect widget recycling; state bugs,// ListView.builder(itemBuilder: (ctx i) => UserTile(user: users[i])) // No key; state mixup on reorder; wrong checkbox checked,ListView.builder(itemBuilder: (ctx i) => UserTile(key: ValueKey(users[i].id) user: users[i])),No keys; widgets recycled incorrectly; TextField in wrong row after reorder,Keys for stateful list items,https://api.flutter.dev/flutter/foundation/Key-class.html
|
|
114
|
-
Nested MediaQuery,Flutter,Performance,Medium,flutter mediaquery nested rebuild context unnecessary of,Using MediaQuery.of in deep widgets; unnecessary rebuilds on any media change,// MediaQuery.of(context).size.width; // Rebuilds on padding textScaleFactor orientation AND size changes,final width = MediaQuery.sizeOf(context).width; // Only notifies when size changes,MediaQuery.of(context) deep in tree; widget rebuilds on every keyboard show/hide,Use specific MediaQuery methods,https://api.flutter.dev/flutter/widgets/MediaQuery-class.html
|
|
115
|
-
Mismatched KSP and Kotlin Versions,Android,Build,Critical,ksp kotlin version mismatch build fail symbol processing,KSP version not matching Kotlin version causes build failures or cryptic errors,ksp = "1.9.24-1.0.20" with kotlin = "2.3.10" // Version mismatch; build fails,"ksp = ""2.3.4"" with kotlin = ""2.3.10""; or ksp = ""2.1.20-2.0.1"" with kotlin = ""2.1.20""",KSP must be compatible with Kotlin version; for Kotlin 2.2+ KSP uses decoupled versioning,Match KSP to Kotlin: Kotlin 2.3.10->KSP 2.3.4; Kotlin 2.1.20->KSP 2.1.20-2.0.1,https://github.com/google/ksp/releases
|
|
116
|
-
Mismatched AGP and Gradle Versions,Android,Build,Critical,agp gradle version incompatible plugin build fail android,Using AGP version that requires a newer Gradle than installed,AGP 9.0.1 with Gradle 8.x // AGP 9 requires Gradle 9.1+; AGP 8.13 requires Gradle 8.13,AGP 9.0.1 with Gradle 9.1+ or AGP 8.13.2 with Gradle 8.13,AGP will fail to sync or produce cryptic errors if Gradle version is too old,Check AGP release notes for minimum Gradle version before upgrading,https://developer.android.com/build/releases/gradle-plugin
|
|
117
|
-
Room with Incompatible Kotlin Version,Android,Build,Critical,room kotlin version incompatible jvm signature crash 2.6,Room 2.6.x with Kotlin 2.0+ causes unexpected jvm signature V error at compile time,"room = ""2.6.1"" with kotlin = ""2.1.20"" // Crashes: unexpected jvm signature V","room = ""2.8.4"" with kotlin = ""2.1.20"" // Room 2.7+ supports Kotlin 2.0+",Room 2.6.x uses old kotlinx-metadata-jvm incompatible with Kotlin 2.0+,Upgrade Room to 2.8.4+ when using Kotlin 2.0+,https://developer.android.com/jetpack/androidx/releases/room
|
|
118
|
-
Upgrading Single Dependency Without Checking Compatibility,Android,Build,High,version upgrade dependency compatibility matrix cascade breaking,Upgrading one library without checking cascade compatibility breaks build,"kotlin = ""2.3.10"" // upgraded but KSP Hilt AGP still on old versions"
|
|
119
|
-
Destructive Migration in Production,Android,Database,Critical,room migration destructive fallback production data loss wipe,Using fallbackToDestructiveMigration(true) in production builds causes all user data to be wiped when database schema changes,Room.databaseBuilder(ctx AppDatabase::class.java "app.db").fallbackToDestructiveMigration(true).build() // In release build: user opens app after update and all data is gone,"Room.databaseBuilder(ctx AppDatabase::class.java ""app.db"").addMigrations(MIGRATION_1_2 MIGRATION_2_3).build() // Proper migrations preserve data",Users lose all local data on app update; causes 1-star reviews and uninstalls,Use fallbackToDestructiveMigration(true) ONLY in debug builds; write proper Migration objects or use @AutoMigration for production,https://developer.android.com/training/data-storage/room/migrating-db-versions
|
|
120
|
-
No Room Migration Defined,Android,Database,Critical,room migration missing crash schema change version IllegalStateException,Incrementing Room @Database version without defining a migration causes IllegalStateException crash on app launch,"@Database(entities = [User::class] version = 2) // No migration from 1 to 2; app crashes: ""A migration from 1 to 2 was required but not found"""
|
|
121
|
-
Room Migration Without Testing,Android,Database,High,room migration test helper untested schema sql alter,Shipping Room migrations without testing them with MigrationTestHelper; migration SQL may silently corrupt data or crash,// Released Migration(1 2) with ALTER TABLE but never tested; typo in column name causes crash on user devices,"@get:Rule val helper = MigrationTestHelper(...); helper.createDatabase(""test"" 1).close(); helper.runMigrationsAndValidate(""test"" 2 true MIGRATION_1_2)",Untested migrations may crash or corrupt data for users who upgrade; cannot reproduce in dev if only testing fresh installs,Test every migration with MigrationTestHelper; test multi-step migration paths (1->2->3),https://developer.android.com/training/data-storage/room/migrating-db-versions#test
|
|
1
|
+
Name,Platform,Category,Severity,Keywords,Description,Bad Example,Good Example,Why Bad,Fix,Reference URL
|
|
2
|
+
God Activity,Android,Architecture,Critical,god activity massive class monolith,Activity with 1000+ lines handling UI business logic and data,class MainActivity { fun fetchData() { db.query() } fun updateUI() },Split into ViewModel + Repository + Composable screens,Violates SRP unmaintainable untestable,Extract ViewModel for logic Repository for data,https://developer.android.com/topic/architecture
|
|
3
|
+
Massive ViewController,iOS,Architecture,Critical,massive viewcontroller mvc god class,ViewController handling all responsibilities,class HomeVC { func callAPI() func parseJSON() func updateUI() },Use MVVM-C with separate ViewModel and Coordinator,Untestable unmaintainable violates SRP,Extract ViewModel Coordinator for navigation,https://developer.apple.com/documentation/swiftui
|
|
4
|
+
Business Logic in Widget,Flutter,Architecture,High,logic widget bloc provider build,Business logic directly in widget build method,Widget build() { final data = http.get(...); return Text(data); },Use BLoC or Provider for business logic separation,Tight coupling impossible to test re-fetches on rebuild,Move logic to BLoC/Cubit inject via BlocProvider,https://bloclibrary.dev/
|
|
5
|
+
Prop Drilling,React Native,Architecture,High,prop drilling passing props deep nesting,Passing props through many component layers,<A data={d}><B data={d}><C data={d}><D data={d}/></C></B></A>,Use Context or state management library,Makes refactoring painful components tightly coupled,Use React Context or Zustand/Redux for shared state,https://react.dev/learn/passing-data-deeply-with-context
|
|
6
|
+
Circular Dependencies,All,Architecture,High,circular dependency import cycle module,Module A depends on B depends on A,moduleA imports moduleB; moduleB imports moduleA,Use dependency inversion interface abstraction,Build failures unclear ownership infinite loops,Introduce interface in shared module,
|
|
7
|
+
Skip Layers in Clean Arch,All,Architecture,Medium,skip layer clean architecture shortcut domain,Presentation layer directly accessing data layer,ViewModel calls Repository bypassing UseCase,Always go through domain layer UseCases,Defeats purpose of clean architecture hard to test,Create UseCase for each business operation,https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html
|
|
8
|
+
Singleton Abuse,All,Architecture,Medium,singleton global state shared instance anti,Using singletons for everything,object AppState { var user; var cart; var settings },Use proper DI with Hilt/Koin/Swinject,Hidden dependencies hard to test race conditions,Use dependency injection framework,
|
|
9
|
+
No Dependency Injection,All,Architecture,High,no di manual instantiation tight coupling,Creating dependencies manually inside classes,class MyVM { val repo = UserRepository(ApiService()) },Use Hilt Koin Swinject or manual constructor DI,Tight coupling impossible to mock or test,Inject dependencies via constructor,https://developer.android.com/training/dependency-injection
|
|
10
|
+
Anemic Domain Model,All,Architecture,Medium,anemic domain model no logic data class,Domain models with only data no behavior,data class User(val name: String) // all logic in service,Add domain logic to models: User.isValid() User.fullName,Domain logic scattered across services,Put behavior with the data it operates on,
|
|
11
|
+
Feature Envy,All,Architecture,Medium,feature envy wrong class responsibility,Class heavily uses another class methods/data,class OrderService { fun calc(cart: Cart) = cart.items.sumOf { it.price } },Move calculation logic to Cart class,Wrong responsibility assignment tight coupling,Move method to class whose data it uses most,
|
|
12
|
+
setState Everywhere,Flutter,State,High,setstate everywhere rebuild widget state,Using setState for all state management,setState(() { _items = await api.fetchItems(); _loading = false; }),Use BLoC Cubit or Riverpod,Unnecessary rebuilds poor separation unmaintainable,Adopt proper state management solution,https://bloclibrary.dev/
|
|
13
|
+
Mutable Shared State,All,State,Critical,mutable shared state race condition thread,Sharing mutable state across threads/isolates,var sharedList = mutableListOf<Item>() // multiple coroutines,Use StateFlow/LiveData or immutable state,Race conditions crashes unpredictable behavior,Use immutable state + state management pattern,
|
|
14
|
+
Re-render Hell,React Native,State,High,rerender performance usememo usecallback memo,Unnecessary re-renders from poor state management,const App = () => { const [count setCount] = useState(0); return <ExpensiveList /> },Use React.memo useMemo useCallback properly,Jank dropped frames battery drain,Memoize expensive components and callbacks,https://react.dev/reference/react/memo
|
|
15
|
+
State in Wrong Place,All,State,Medium,state wrong scope local global misplaced,Putting local state in global store or vice versa,Redux store: { modalOpen: false buttonHover: false },Keep UI state local share only what needs sharing,Unnecessary complexity and re-renders,Local state for UI global for shared business data,
|
|
16
|
+
No Single Source of Truth,All,State,High,duplicate state sync inconsistent ssot,Same data stored in multiple places,var cachedUser in VM; var savedUser in Repo; var displayUser in UI,Single source of truth with reactive streams,Data gets out of sync inconsistent UI,Use Room/CoreData as SSOT observe with Flow/Combine,https://developer.android.com/topic/architecture/data-layer
|
|
17
|
+
Direct State Mutation,All,State,High,direct mutation state modify side effects,Modifying state objects directly,_state.items.add(newItem); notifyListeners(),_state = _state.copyWith(items: [..._state.items newItem]),Side effects lost change history broken equality,Always create new state objects via copy/copyWith,
|
|
18
|
+
Missing Error State,All,State,High,no error handling state loading empty,Not handling loading error and empty states,if (data != null) showData(data),sealed class UiState { Loading Success Error Empty },Users see blank screen on error no feedback,Use sealed class/enum for all possible UI states,
|
|
19
|
+
Storing Derived State,All,State,Medium,derived computed state redundant duplicate,Storing values that can be computed,var items; var filteredItems; var itemCount,Compute filteredItems and count from items,State sync issues stale data extra storage,Use computed properties or selectors,
|
|
20
|
+
Blocking Main Thread,All,UI,Critical,main thread ui anr freeze jank block,Doing heavy work on the main/UI thread,fun onCreate() { val data = database.queryAll() },Use coroutines/async with Dispatchers.IO,ANR dialog frozen UI dropped frames,Move heavy work to background thread/coroutine,https://developer.android.com/kotlin/coroutines
|
|
21
|
+
Hardcoded Strings,All,UI,Medium,hardcoded string i18n localization resource,Hardcoding user-facing strings in code,"Text(""Welcome back!"")",Text(stringResource(R.string.welcome_back)),Cannot localize accessibility issues,Use string resources for all user-facing text,https://developer.android.com/guide/topics/resources/string-resource
|
|
22
|
+
Hardcoded Colors,All,UI,Medium,hardcoded color hex theme design system,Using hex colors directly instead of theme,Box(modifier = Modifier.background(Color(0xFF2196F3))),Box(modifier = Modifier.background(MaterialTheme.colorScheme.primary)),No dark mode support inconsistent theming,Use theme system colors,https://developer.android.com/develop/ui/compose/designsystems/material3
|
|
23
|
+
Nested Scrolling Conflict,All,UI,High,nested scroll recyclerview scrollview conflict jank,ScrollView inside ScrollView without coordination,ScrollView { RecyclerView { } },Use NestedScrollView or single LazyColumn,Janky scroll stolen gestures broken UX,Use single scrollable container,https://developer.android.com/develop/ui/compose/lists
|
|
24
|
+
Missing Loading States,All,UI,High,no loading state blank screen async,Not showing loading indicators,if (data != null) show(data) // nothing while loading,Show skeleton/shimmer while loading,Users think app is broken,Always show loading feedback for async operations,
|
|
25
|
+
Layout Shift on Load,All,UI,Medium,layout shift cls jump content pop,Content jumping when images/data loads,Image loads and pushes text down,Reserve space with fixed aspect ratio or placeholder,Disorienting UX accidental taps,Use fixed dimensions or aspect ratio containers,
|
|
26
|
+
Ignoring Safe Area,All,UI,High,safe area notch cutout inset system bars,Content behind notch or system bars,Content goes behind status bar,Respect safe area insets on all edges,Content hidden behind system UI,Use SafeArea/safeAreaInset/WindowInsets,https://developer.android.com/develop/ui/compose/layouts/insets
|
|
27
|
+
No Image Caching,All,Performance,High,image cache memory network reload bandwidth,Loading images from network every time,Image.network(url) // no caching,CachedNetworkImage(imageUrl: url placeholder: shimmer),Wasted bandwidth slow loading,Use Coil/Glide/Kingfisher/CachedNetworkImage,
|
|
28
|
+
Memory Leak in Callback,All,Memory,Critical,memory leak callback listener retain register,Registering listeners without cleanup,onStart() { EventBus.register(this) } // never unregistered,Unregister in onStop/dispose/cleanup,Memory grows app crashes OOM,Always unregister in corresponding lifecycle method,
|
|
29
|
+
Unnecessary Recomposition,Android,Performance,High,recomposition compose unstable lambda key,Compose recomposing when it should not,LazyColumn { items(list) { Button(onClick = { doSomething(it) }) } },Use remember/derivedStateOf stable lambdas and keys,Wasted CPU jank poor battery life,Use key parameter stable lambdas Immutable annotations,https://developer.android.com/develop/ui/compose/performance
|
|
30
|
+
Large Bundle Size,React Native,Performance,Medium,bundle size hermes ram assets tree shake,App bundle too large,import _ from 'lodash' // entire library,import debounce from 'lodash/debounce',Slow download slow install,Tree-shake imports enable Hermes optimize assets,https://reactnative.dev/docs/hermes
|
|
31
|
+
No Pagination,All,Performance,High,no pagination load all memory oom list,Loading entire dataset at once,val allItems = api.getAllItems() // 10000 items,Use Paging3/pagination load 20 at a time,OOM crash slow response,Implement cursor/offset pagination,https://developer.android.com/topic/libraries/architecture/paging/v3-overview
|
|
32
|
+
Synchronous Network Call,All,Performance,Critical,synchronous network main thread block anr,Making network calls on main thread,val response = URL(apiUrl).readText() // blocks,withContext(Dispatchers.IO) { api.fetch() },ANR frozen UI app killed by system,Always use async/await coroutines or callbacks,https://developer.android.com/kotlin/coroutines
|
|
33
|
+
Widget Rebuild Storm,Flutter,Performance,High,widget rebuild unnecessary build frequent,Entire widget tree rebuilding on minor change,setState(() { _title = newTitle; }) // rebuilds everything,Use BLoC/Consumer/Selector to scope rebuilds,Poor performance janky scrolling,Scope rebuilds to affected widgets only,https://docs.flutter.dev/perf/best-practices
|
|
34
|
+
Not Handling Lifecycle,Android,Lifecycle,Critical,lifecycle activity fragment destroy recreate rotation,Not handling config changes and lifecycle,Store data in Activity fields lost on rotation,Use ViewModel to survive configuration changes,Data loss on rotation crash on backgrounding,Use ViewModel + SavedStateHandle,https://developer.android.com/topic/libraries/architecture/viewmodel
|
|
35
|
+
Retain Cycle,iOS,Memory,Critical,retain cycle strong reference memory leak arc closure,Strong reference cycle between objects,closure = { self.doWork() } // strong capture,Use [weak self] or [unowned self] in closures,Memory never freed app memory grows,Use [weak self] in closures that capture self,https://docs.swift.org/swift-book/documentation/the-swift-programming-language/automaticreferencecounting/
|
|
36
|
+
Not Disposing Controllers,Flutter,Lifecycle,High,dispose controller textediting animation scroll leak,Not calling dispose on controllers,final ctrl = TextEditingController(); // no dispose,@override void dispose() { ctrl.dispose(); super.dispose(); },Memory leak resource leak potential crashes,Override dispose() clean up all controllers,https://api.flutter.dev/flutter/widgets/State/dispose.html
|
|
37
|
+
Missing Cleanup in useEffect,React Native,Lifecycle,High,useeffect cleanup subscription listener return,useEffect without cleanup function,useEffect(() => { socket.connect(); }),useEffect(() => { socket.connect(); return () => socket.disconnect(); }),Memory leak zombie listeners stale callbacks,Always return cleanup function from useEffect,https://react.dev/reference/react/useEffect
|
|
38
|
+
Ignoring App Lifecycle,All,Lifecycle,Medium,background foreground app lifecycle pause resume,Not handling app going to background/foreground,Keep timers and connections running in background,Pause work on background resume on foreground,Battery drain wasted resources,Use LifecycleObserver/AppDelegate/WidgetsBindingObserver,https://developer.android.com/guide/components/activities/activity-lifecycle
|
|
39
|
+
Deep Nesting Navigation,All,Navigation,Medium,deep nesting navigation back stack levels,Deeply nested navigation stacks 6+ levels,Screen A -> B -> C -> D -> E -> F,Use flat navigation with tabs max 3-4 levels,Confusing UX user gets lost,Flatten navigation use tabs or modal for side flows,
|
|
40
|
+
No Deep Link Support,All,Navigation,Medium,deep link universal link app link url,App has no deep linking support,Only navigate via taps inside the app,Support deep links for all major screens,Cannot share content poor marketing,Implement deep linking from the start,https://developer.android.com/training/app-links
|
|
41
|
+
Losing Navigation State,All,Navigation,High,navigation state lost backstack destroy death,Navigation state lost on process death,Navigate back and screens are blank,Save and restore navigation state,Users lose their place,Use SavedStateHandle/StateRestoration,https://developer.android.com/topic/libraries/architecture/saving-states
|
|
42
|
+
Hard-coded Routes,All,Navigation,Medium,hardcoded route string navigation typo,Using raw strings for navigation routes,navigator.push('/home/profile/123'),Use typed routes or route constants with type safety,Typo-prone no compile-time safety,Use type-safe navigation,https://developer.android.com/guide/navigation/design/type-safety
|
|
43
|
+
No Back Handler,Android,Navigation,High,back handler predictive back gesture exit,Not handling system back properly,System back closes app from any screen,Use BackHandler or predictive back API,Users accidentally exit app,Handle back press with confirmation,https://developer.android.com/guide/navigation/custom-back/predictive-back-gesture
|
|
44
|
+
No Offline Support,All,Network,Medium,offline cache first network connection,App completely unusable without network,if (!isConnected) showError('No internet'),Cache data locally show cached + sync online,Unusable on poor connection,Implement offline-first with local cache,
|
|
45
|
+
No Request Retry,All,Network,Medium,retry exponential backoff network failure,No retry logic for failed requests,val response = api.getData() // fails once gives up,Implement exponential backoff retry max 3 attempts,Transient failures shown as errors,Add retry with exponential backoff,
|
|
46
|
+
Ignoring HTTP Errors,All,Network,High,http error status code ignore 4xx 5xx,Not handling non-200 HTTP status codes,val data = response.body() // assumes always 200,Check status code handle 4xx and 5xx properly,Silent failures corrupted data,Handle all HTTP status codes,
|
|
47
|
+
No Request Cancellation,All,Network,Medium,cancel request dispose viewmodel navigate away,Not cancelling requests when leaving screen,API calls continue after user navigates away,Cancel requests in onCleared/dispose/cleanup,Wasted resources updating destroyed UI,Tie request lifecycle to screen lifecycle,
|
|
48
|
+
Trusting Server Data,All,Network,High,trust server validation input sanitize null,Blindly trusting all data from server,val name = response.name!!; textView.text = name,Validate and sanitize all server responses,Crashes on null/malformed data,Validate all fields handle missing data,
|
|
49
|
+
No Unit Tests,All,Testing,High,no tests unit test coverage regression,No automated tests in the project,Ship code without any tests,Write unit tests for ViewModels repositories logic,Regression bugs fear of refactoring,Start with ViewModel/BLoC tests then expand,https://developer.android.com/training/testing
|
|
50
|
+
Hardcoded API Keys,All,Security,Critical,api key hardcoded secret exposed source,API keys committed to source code,const val API_KEY = 'sk-abc123...',Use BuildConfig/xcconfig/env vars and .gitignore,Keys exposed in decompiled APK/IPA,Store in local.properties/xcconfig never commit,https://owasp.org/www-project-mobile-top-10/
|
|
51
|
+
No SSL Pinning,All,Security,High,ssl pinning certificate mitm attack,No certificate pinning for API calls,OkHttpClient() // trusts any valid cert,Implement certificate/public key pinning,Man-in-the-middle attacks,Pin server certificate or public key,https://developer.android.com/privacy-and-security/security-config#CertificatePinning
|
|
52
|
+
Storing Sensitive in Prefs,All,Security,Critical,sharedpreferences userdefaults plaintext sensitive token,Storing tokens/passwords in plain preferences,SharedPreferences.putString('token' jwt),Use EncryptedSharedPreferences/Keychain/flutter_secure_storage,Tokens readable by rooted device,Use platform secure storage,https://developer.android.com/reference/androidx/security/crypto/EncryptedSharedPreferences
|
|
53
|
+
No Input Validation,All,Security,High,input validation xss injection sanitize,Not validating user input,textView.text = userInput // direct usage,Validate sanitize and escape all user inputs,XSS injection SQL injection crashes,Validate format length content of all inputs,
|
|
54
|
+
No ProGuard R8,Android,Security,Medium,proguard r8 obfuscation minify shrink,Not enabling code shrinking,minifyEnabled false // in build.gradle,minifyEnabled true with proper proguard-rules.pro,Larger APK reverse engineering easy,Enable R8 with proper keep rules,https://developer.android.com/build/shrink-code
|
|
55
|
+
Logging Sensitive Data,All,Security,High,log sensitive password token pii debug production,Logging passwords tokens or PII,Log.d(TAG 'User token: $token'),Never log sensitive data use redaction in production,Credentials leaked via logs,Strip debug logs in release configure log levels,
|
|
56
|
+
Composable Side Effects,Android,Compose,Critical,compose side effect launched disposable remember coroutine,Running side effects directly in composable body without LaunchedEffect,@Composable fun Screen() { api.fetchData() // runs on every recomposition },@Composable fun Screen() { LaunchedEffect(Unit) { api.fetchData() } },Runs on every recomposition; infinite network calls; crashes,Use LaunchedEffect DisposableEffect or rememberCoroutineScope,https://developer.android.com/develop/ui/compose/side-effects
|
|
57
|
+
State Hoisting Failure,Android,Compose,High,compose state hoisting remember mutablestateof local,Keeping state local in child composable instead of hoisting to parent,@Composable fun Search() { var query by remember { mutableStateOf('') } },@Composable fun Search(query: String onQueryChange: (String) -> Unit),Parent cannot observe or control child state; breaks unidirectional flow,Hoist state to lowest common ancestor; pass state down events up,https://developer.android.com/develop/ui/compose/state#state-hoisting
|
|
58
|
+
Remember with Wrong Key,Android,Compose,High,compose remember key recomposition stale cache invalidate,Using remember without keys causing stale cached values,val data = remember { expensiveCompute(input) } // stale when input changes,val data = remember(input) { expensiveCompute(input) } // recomputes on change,Cached value never updates when inputs change; shows stale data,Pass keys to remember that trigger recomputation,https://developer.android.com/develop/ui/compose/side-effects#remember
|
|
59
|
+
derivedStateOf Misuse,Android,Compose,Medium,compose derivedstateof unnecessary overhead recomposition filter,Using derivedStateOf for values that change with every state change,val text = remember { derivedStateOf { input.value } } // unnecessary,val filteredList = remember { derivedStateOf { list.filter { it.isActive } } },derivedStateOf adds overhead; only useful when result changes less often than input,Use derivedStateOf only when output changes less frequently than input,https://developer.android.com/develop/ui/compose/side-effects#derivedstateof
|
|
60
|
+
Unstable Lambda in Compose,Android,Compose,High,compose lambda recomposition unstable capture remember callback,Passing unstable lambdas causing unnecessary recompositions,LazyColumn { items(list) { Button(onClick = { viewModel.select(it) }) } },val onSelect = remember { { item: Item -> viewModel.select(item) } },Unstable lambda prevents skipping recomposition of items; janky scrolling,Use remember for lambdas or enable Strong Skipping Mode,https://developer.android.com/develop/ui/compose/performance/stability
|
|
61
|
+
GlobalScope Coroutine,Android,Coroutine,Critical,globalscope coroutine launch leak lifecycle cancel fire forget,Using GlobalScope instead of viewModelScope or lifecycleScope,GlobalScope.launch { api.fetchData() },viewModelScope.launch { api.fetchData() },Never cancelled; outlives component; memory leak; ignores lifecycle,Use viewModelScope lifecycleScope or custom CoroutineScope,https://developer.android.com/kotlin/coroutines/coroutines-best-practices
|
|
62
|
+
runBlocking on Main,Android,Coroutine,Critical,runblocking main thread anr block coroutine bridge,Using runBlocking on Main thread to bridge sync and async code,fun getData() = runBlocking { api.fetch() } // blocks main thread,suspend fun getData() = api.fetch() // or use viewModelScope.launch,ANR after 5 seconds; frozen UI; app killed by system,Never use runBlocking on main; use suspend functions or launch,https://developer.android.com/kotlin/coroutines/coroutines-best-practices
|
|
63
|
+
Collecting Flow in ViewModel init,Android,Coroutine,High,flow collect init viewmodel launch stateflow repeatonlifecycle,Collecting Flow in ViewModel init without proper scoping,init { viewModelScope.launch { repo.data.collect { _state.value = it } } },val state = repo.data.stateIn(viewModelScope SharingStarted.WhileSubscribed(5000) initial),Flow collected even when UI not visible; wasted resources,Use stateIn with WhileSubscribed for lifecycle-aware collection,https://developer.android.com/kotlin/flow/stateflow-and-sharedflow
|
|
64
|
+
Not Using repeatOnLifecycle,Android,Lifecycle,High,repeatonlifecycle flow collect lifecycle started activity fragment,Collecting Flow in Activity/Fragment without lifecycle awareness,lifecycleScope.launch { viewModel.state.collect { updateUI(it) } },lifecycleScope.launch { repeatOnLifecycle(STARTED) { viewModel.state.collect { updateUI(it) } } },Collects in background wasting resources; potential crashes on destroyed views,Use repeatOnLifecycle or collectAsStateWithLifecycle in Compose,https://developer.android.com/topic/libraries/architecture/coroutines#lifecycle-aware
|
|
65
|
+
ViewModel Factory Boilerplate,Android,Architecture,Medium,viewmodel factory provider deprecated assistedinject creationextras,Writing manual ViewModel factory instead of using Hilt or CreationExtras,class MyVMFactory(val repo: Repo) : ViewModelProvider.Factory { override fun <T> create() },@HiltViewModel class MyVM @Inject constructor(val repo: Repo) : ViewModel(),Unnecessary boilerplate; error-prone; manual dependency wiring,Use @HiltViewModel or CreationExtras (AGP 2.5+),https://developer.android.com/training/dependency-injection/hilt-android
|
|
66
|
+
Hilt Missing EntryPoint,Android,DI,High,hilt entrypoint inject contentprovider broadcastreceiver workmanager,Not using @EntryPoint for non-standard Hilt injection targets,class MyReceiver : BroadcastReceiver() { val repo = UserRepository() // manual },@AndroidEntryPoint class MyReceiver : BroadcastReceiver() @Inject lateinit var repo: Repo,Manual instantiation; missing initialization; test-unfriendly,Use @EntryPoint for WorkManager ContentProvider BroadcastReceiver,https://developer.android.com/training/dependency-injection/hilt-android#not-supported
|
|
67
|
+
Exposing MutableStateFlow,Android,State,High,mutablestateflow expose public private backing field viewmodel,Exposing MutableStateFlow publicly from ViewModel,val state = MutableStateFlow(Initial) // public mutable,private val _state = MutableStateFlow(Initial); val state: StateFlow<X> = _state.asStateFlow(),Views can modify ViewModel state directly; breaks UDF,Use private MutableStateFlow with public StateFlow accessor,https://developer.android.com/kotlin/flow/stateflow-and-sharedflow
|
|
68
|
+
SwiftUI Body Heavy Computation,iOS,SwiftUI,High,swiftui body computed property heavy performance view,Doing expensive work in SwiftUI body property,var body: some View { let filtered = items.filter { expensive($0) }; List(filtered) },@State private var filtered = []; func updateFilter() { filtered = items.filter { } },Body runs on every re-render; expensive filter runs repeatedly,Compute in onChange or task; cache results in @State,https://developer.apple.com/documentation/swiftui
|
|
69
|
+
ObservableObject Over-Publishing,iOS,SwiftUI,High,observableobject published objectwillchange unnecessary rerender,Too many @Published properties causing unnecessary view updates,class VM: ObservableObject { @Published var a; @Published var b; @Published var c },Use @Observable macro (iOS 17+) for granular tracking,Every @Published change triggers all observing views to re-render,Use @Observable or split into multiple ObservableObjects,https://developer.apple.com/documentation/observation/observable()
|
|
70
|
+
Force Unwrapping Optionals,iOS,Swift,Critical,force unwrap optional bang crash nil unexpected,Using ! to force unwrap optionals that might be nil,let name = user.name! // crashes if nil,guard let name = user.name else { return },Runtime crash if value is nil; common source of production crashes,Use guard let if let or ?? with defaults,https://docs.swift.org/swift-book/documentation/the-swift-programming-language/optionalchaining/
|
|
71
|
+
setState with API Call,Flutter,State,High,setstate api call network widget build futurebuilder,Calling API directly in widget with setState for result,setState(() { data = await api.fetch(); }) // in initState,Use BLoC/Riverpod/FutureBuilder for async data,Mixed concerns; can't test; race conditions on rapid rebuilds,Separate data fetching from UI using state management,https://docs.flutter.dev/data-and-backend/state-mgmt/options
|
|
72
|
+
BuildContext Across Async Gap,Flutter,Architecture,Critical,buildcontext async gap mounted scaffold navigator context,Using BuildContext after await when widget might be unmounted,await api.fetch(); ScaffoldMessenger.of(context).showSnackBar(snack),if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar(snack),Widget may be unmounted; context invalid; crash or wrong behavior,Check mounted before using context after await,https://dart.dev/tools/linter-rules/use_build_context_synchronously
|
|
73
|
+
Provider Without Select,Flutter,Performance,Medium,provider select watch read consumer unnecessary rebuild,Using context.watch when only one field needed causing full rebuilds,final state = context.watch<AppState>(); // rebuilds on any change,final name = context.select<AppState String>((s) => s.name);,Entire widget rebuilds when any AppState field changes,Use select to pick specific fields; minimizes rebuilds,https://pub.dev/packages/provider
|
|
74
|
+
Inline Styles in RN,React Native,UI,Medium,inline style stylesheet create performance object allocation,Creating style objects inline in render causing re-allocation,<View style={{flex: 1 backgroundColor: 'red'}} />,<View style={styles.container} />; const styles = StyleSheet.create({container: {flex: 1}}),New object allocated every render; breaks PureComponent memo,Use StyleSheet.create outside component,https://reactnative.dev/docs/stylesheet
|
|
75
|
+
Console.log in Production,React Native,Performance,Medium,console log production performance bridge debug remove strip,Leaving console.log statements in production build,console.log('user data:' JSON.stringify(userObject)),if (__DEV__) console.log('debug info'); // or use babel-plugin-transform-remove-console,Serialization overhead; sensitive data exposure; bridge congestion,Use babel plugin to strip console in production,https://reactnative.dev/docs/performance
|
|
76
|
+
Uncontrolled re-renders in List,React Native,Performance,High,flatlist rerender key extractor item separator optimization,FlatList items re-rendering on every state change,<FlatList data={items} renderItem={({item}) => <Item data={item} store={entireStore} />} />,<FlatList data={items} renderItem={renderItem} keyExtractor={keyExtractor} getItemLayout={getItemLayout} />,Entire list re-renders; dropped frames; janky scrolling,Use React.memo keyExtractor getItemLayout; minimize item props,https://reactnative.dev/docs/flatlist
|
|
77
|
+
Async Storage for Sensitive Data,React Native,Security,Critical,asyncstorage sensitive token password plaintext unencrypted,Storing tokens or passwords in AsyncStorage (unencrypted),await AsyncStorage.setItem('token' jwtToken),await Keychain.setGenericPassword('user' token {service: 'auth'}),AsyncStorage is plaintext; readable on rooted devices,Use react-native-keychain for sensitive data,https://github.com/oblador/react-native-keychain
|
|
78
|
+
Platform Channel in Hot Path,Flutter,Performance,High,platform channel method invocation hot path loop frequent native,Calling platform channels in loops or animations,for (item in items) { await methodChannel.invokeMethod('process' item); },final results = await methodChannel.invokeMethod('processBatch' items);,Each call has ~0.5ms overhead; 100 calls = 50ms; jank during animation,Batch platform channel calls; use Pigeon for type-safe interface,https://docs.flutter.dev/platform-integration/platform-channels
|
|
79
|
+
No Error Boundary,React Native,Architecture,High,error boundary crash fallback react native component tree,No error boundaries causing entire app crash on JS error,// No ErrorBoundary; one component crash takes down entire app,class ErrorBoundary extends React.Component { static getDerivedStateFromError(e) { return {hasError: true} } },Single component error crashes entire React tree,Wrap screen-level and critical components in ErrorBoundary,https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary
|
|
80
|
+
Magic Numbers,All,Code Quality,Medium,magic number constant named value meaning readability,Using unexplained numeric literals in code,if (retryCount > 3) { delay(2000) },if (retryCount > MAX_RETRIES) { delay(RETRY_DELAY_MS) },Unclear intent; hard to change; scattered duplicate values,Extract to named constants with descriptive names,
|
|
81
|
+
Magic Numbers,All,Clean Code,Medium,magic number constant named hardcoded value readability,Hardcoded numeric values with no explanation scattered through code,if (retryCount > 3) { delay(5000) },companion object { const val MAX_RETRIES = 3; const val RETRY_DELAY_MS = 5000L }; if (retryCount > MAX_RETRIES) delay(RETRY_DELAY_MS),Unreadable; changing value requires finding all instances; no context for why 3 or 5000,Extract to named constants with meaningful names,https://developer.android.com/kotlin/style-guide
|
|
82
|
+
God ViewModel,Android,Clean Code,Critical,god viewmodel massive 1000 lines srp single responsibility bloated,ViewModel handling 10+ responsibilities: auth + navigation + analytics + UI state + validation + caching,class CheckoutViewModel { fun processPayment(); fun validateCard(); fun applyDiscount(); fun updateCart(); fun loadAddress(); fun trackEvent(); fun refreshUser() },Split: CartViewModel + PaymentViewModel + AddressViewModel; Use UseCases for business logic,Untestable; impossible to reason about; merge conflict magnet; 1500+ lines,Extract UseCases; split by screen/feature; ViewModel orchestrates not implements,https://developer.android.com/topic/architecture/ui-layer
|
|
83
|
+
Primitive Obsession,All,Clean Code,Medium,primitive obsession string int type safety wrapper value class,Using raw String/Int where domain types provide safety,fun processOrder(orderId: String customerId: String productId: String amount: Int),@JvmInline value class OrderId(val value: String); @JvmInline value class CustomerId(val value: String); fun processOrder(orderId: OrderId customerId: CustomerId),Easy to swap orderId and customerId accidentally; no compile-time safety; bugs at runtime,Use Kotlin value classes or typealiases for domain primitives,https://kotlinlang.org/docs/inline-classes.html
|
|
84
|
+
Callback Hell,All,Clean Code,High,callback hell nested pyramid async completion handler indentation,Deeply nested callbacks making code unreadable and error-prone,api.login { user -> api.getProfile(user.id) { profile -> api.getOrders(profile.id) { orders -> updateUI(orders) } } },val user = api.login(); val profile = api.getProfile(user.id); val orders = api.getOrders(profile.id); updateUI(orders) // suspend functions,Pyramid of doom; error handling at each level; impossible to follow flow; can't cancel,Use suspend functions (Kotlin); async/await (Swift/JS); or Flow/Combine,https://developer.android.com/kotlin/coroutines
|
|
85
|
+
Stringly Typed APIs,All,Clean Code,Medium,string typed enum sealed navigation route key preference magic string,Using raw strings as identifiers instead of enums or sealed types,"navController.navigate(""detail/123""); prefs.getString(""theme""); when (status) { ""loading"" -> ...","@Serializable data class DetailRoute(val id: String); navController.navigate(DetailRoute(""123"")); enum class Theme { LIGHT DARK }",Typos cause runtime crashes; no refactoring safety; no exhaustive when; find-and-replace breaks,Use enums sealed interfaces or @Serializable data classes for type safety,https://developer.android.com/guide/navigation/design/type-safety
|
|
86
|
+
Long Parameter List,All,Clean Code,Medium,long parameter list function arguments config builder data class,Functions with 5+ parameters; hard to remember order; easy to swap arguments,fun createUser(name: String email: String age: Int city: String country: String bio: String avatar: String premium: Boolean),data class CreateUserRequest(val name: String val email: String val age: Int val city: String); fun createUser(request: CreateUserRequest),Arguments easily swapped; hard to read at call site; adding new param requires changing all callers,Group into data class or builder pattern; use named arguments in Kotlin,https://developer.android.com/kotlin/style-guide
|
|
87
|
+
Feature Envy,All,Clean Code,Medium,feature envy method class responsibility data access encapsulation,Method that uses more data from another class than its own,fun OrderViewModel.calculateTotal() { val items = cart.items; val tax = cart.taxRate; val discount = cart.discount; return items.sumOf { it.price } * (1 + tax) - discount },fun Cart.calculateTotal(): Double { return items.sumOf { it.price } * (1 + taxRate) - discount }; // Method belongs in Cart,Breaks encapsulation; changes to Cart internals require ViewModel changes; tight coupling,Move method to the class whose data it primarily uses,
|
|
88
|
+
No Error Handling Strategy,All,Maintainability,Critical,error handling strategy result either sealed exception crash production,Inconsistent error handling; mix of try-catch exceptions Result and nullable returns,fun getUser(): User = api.getUser() // Throws; fun getOrders(): List<Order>? // Nullable; fun getCart(): Result<Cart> // Result,Consistent: suspend fun getUser(): Result<User>; // Always Result; ViewModel handles fold(onSuccess onFailure),Unpredictable API surface; callers don't know what to expect; crashes in production,Adopt consistent strategy: Result<T> or sealed class or Arrow Either across entire codebase,https://developer.android.com/kotlin/coroutines/coroutines-best-practices
|
|
89
|
+
Tight Coupling to Framework,All,Maintainability,High,tight coupling framework dependency inversion testability android context,Business logic directly depending on Android framework classes,class UserRepository(private val context: Context) { fun save(user: User) { context.getSharedPreferences(...).edit().putString(user.json).apply() } },interface UserStorage { suspend fun save(user: User) }; class SharedPrefUserStorage(context: Context) : UserStorage; class UserRepository(private val storage: UserStorage),Can't unit test without Android; business logic untestable; migration impossible,Dependency inversion: depend on interfaces not implementations,https://developer.android.com/training/dependency-injection
|
|
90
|
+
Missing Mapper Layer,All,Maintainability,High,mapper dto entity domain model separation layer boundary clean,Domain models directly using API DTOs or database entities; tightly coupled,"@Entity data class User(@PrimaryKey val id: String @Json(name = ""first_name"") val firstName: String) // Used everywhere",Separate: UserDto (API) + UserEntity (DB) + User (domain); fun UserDto.toDomain() fun User.toEntity(),API change breaks UI; database schema change requires UI update; no boundary isolation,Create mapper functions at layer boundaries; domain model is source of truth,https://developer.android.com/topic/architecture/data-layer
|
|
91
|
+
No Logging Strategy,All,Maintainability,Medium,logging strategy timber debug release production strip sanitize,Inconsistent logging; Log.d everywhere; sensitive data in production logs,"Log.d(""TAG"" ""User password: $password""); Log.d(""TAG"" ""Token: $token"")","Timber.d(""Login attempt for %s"" username); // Stripped in release; no sensitive data; structured",Sensitive data leaked in production logs; inconsistent tags; no way to strip debug logs,Use Timber; configure release tree; strip debug logs with R8; never log PII,https://github.com/JakeWharton/timber
|
|
92
|
+
Hardcoded Strings in UI,All,Maintainability,Medium,hardcoded string ui localization i18n l10n translation resource,Hardcoded UI strings making localization impossible,"Text(""Welcome back!""); Button(""Submit Order"")","Text(stringResource(R.string.welcome_back)); // or LocalizedStringKey(""welcome_back"") in SwiftUI",Can't translate app; changing copy requires code change and redeploy; no RTL support,Extract all user-visible strings to resources; use string formatting for dynamic content,https://developer.android.com/guide/topics/resources/localization
|
|
93
|
+
Ignoring Code Formatting,All,Maintainability,Low,code formatting ktfmt ktlint spotless detekt lint consistent style,Inconsistent code formatting; tabs vs spaces; brace style wars; messy PRs,Mixed formatting: some files use 2-space indent others 4-space; trailing whitespace; no linting,"// build.gradle.kts: plugins { id(""com.diffplug.spotless"") }; spotless { kotlin { ktfmt().googleStyle() } }; // Enforced in CI",Noisy diffs; style debates in PRs; inconsistent codebase appearance,Configure ktfmt/ktlint with Spotless plugin; enforce in CI pre-commit hook,https://developer.android.com/kotlin/style-guide
|
|
94
|
+
No Dependency Injection,All,Scalability,Critical,dependency injection di hilt koin manual creation testability coupling,Manually creating dependencies everywhere; tight coupling; untestable,class UserViewModel { val repo = UserRepository(ApiClient() AppDatabase.getInstance().userDao()) },@HiltViewModel class UserViewModel @Inject constructor(private val repo: UserRepository) : ViewModel(),Can't substitute test doubles; changing dependency requires modifying every consumer; circular deps,Use Hilt (Android) or Koin; constructor injection; interface bindings,https://developer.android.com/training/dependency-injection/hilt-android
|
|
95
|
+
Shared Mutable State,All,Scalability,Critical,shared mutable state global singleton concurrency race condition thread safety,Global mutable state accessed from multiple threads without synchronization,object AppState { var currentUser: User? = null; var cartItems = mutableListOf<Item>() }; // Modified from any thread,private val _user = MutableStateFlow<User?>(null); val user: StateFlow<User?> = _user.asStateFlow() // Thread-safe; single writer,Race conditions; data corruption; impossible to reproduce bugs; crashes under load,Use StateFlow/LiveData for reactive state; Mutex for critical sections; immutable data classes,https://developer.android.com/kotlin/flow/stateflow-and-sharedflow
|
|
96
|
+
Monolithic Navigation,All,Scalability,High,monolithic navigation graph single navgraph nested module scale route,Single navigation graph with all 50+ screens; merge conflicts; can't modularize,"NavHost { composable(""home"") { }; composable(""search"") { }; composable(""profile"") { }; ... 50 more routes in one file }",// Each feature module exposes navigation: fun NavGraphBuilder.homeGraph() { composable<HomeRoute> { HomeScreen() } }; // Root: NavHost { homeGraph(); searchGraph(); profileGraph() },Monolithic file; every team edits same navigation; can't parallelize feature development,Nested nav graphs per feature module; each module owns its routes,https://developer.android.com/guide/navigation/design/nested-graphs
|
|
97
|
+
No Tests,All,Testing,Critical,no test coverage untested unit integration ship pray,Shipping code with zero automated tests,func updatePrice(newPrice: Decimal) { product.price = newPrice; notifyObservers() } // No tests anywhere,@Test fun updatePrice_updatesValue() { viewModel.updatePrice(9.99); assertEquals(9.99 viewModel.product.value.price) },One bug fix breaks 3 other features; regression on every release; fear of refactoring,Write tests for critical business logic first; aim for 80%+ coverage on domain layer,https://developer.android.com/training/testing
|
|
98
|
+
Testing Implementation Details,All,Testing,High,test implementation detail brittle fragile mock verify internal,Tests that verify HOW code works instead of WHAT it does; break on refactor,verify(exactly = 1) { repo.save(any()) }; // Tests internal call; breaks if implementation changes,val result = viewModel.submitOrder(order); assertEquals(OrderStatus.CONFIRMED result.status) // Tests behavior,Tests break on every refactor even when behavior unchanged; zero confidence; test maintenance hell,Test public behavior and outputs; don't verify internal method calls unless side-effect is the contract,https://testing.googleblog.com/2013/08/testing-on-toilet-test-behavior-not.html
|
|
99
|
+
Flaky Tests in CI,All,Testing,High,flaky test intermittent fail pass ci unreliable timing race condition,Tests that randomly pass/fail; team starts ignoring CI results,@Test fun testNetworkCall() { Thread.sleep(5000); assertTrue(result.isSuccess) } // Timing dependent,@Test fun testNetworkCall() = runTest { val result = fakeRepo.getData(); assertTrue(result.isSuccess) } // Deterministic,Team ignores CI failures; broken code merges; flaky tests erode trust in entire test suite,Use fakes instead of mocks; use TestCoroutineDispatcher; avoid Thread.sleep; deterministic tests,https://developer.android.com/training/testing/fundamentals
|
|
100
|
+
No Single Source of Truth,All,Data,Critical,single source truth ssot cache api database stale inconsistent duplicated,Same data stored in multiple places; becomes inconsistent,var cachedUser: User? = null; fun getUser(): User { cachedUser = api.getUser(); return cachedUser!! } // Also in Room; also in ViewModel,fun getUser(): Flow<User> = userDao.observe().onStart { refreshFromNetwork() } // Room is SSOT,Stale data shown; user sees different info on different screens; cache invalidation bugs,Make local database (Room) single source of truth; network refreshes database; UI observes database,https://developer.android.com/topic/architecture/data-layer#source-of-truth
|
|
101
|
+
Repository Returns Entity,All,Data,Medium,repository room entity dto leak domain layer boundary separation,Repository exposing Room entities or API DTOs directly to ViewModel/UI,fun getUsers(): Flow<List<UserEntity>> // Room entity with @ColumnInfo annotations leaked to UI,fun getUsers(): Flow<List<User>> // Clean domain model; mapped in repository; UI decoupled from DB schema,Database schema change forces UI update; API response change ripples through entire app,Map Entity → Domain model in repository; UI never sees database annotations or API field names,https://developer.android.com/topic/architecture/data-layer
|
|
102
|
+
Fire and Forget Coroutine,Android,Coroutine,High,fire forget coroutine launch exception lost crash silent scope,Launching coroutine without handling exceptions; silent failures,viewModelScope.launch { api.saveData(data) } // Exception silently swallowed by default handler,viewModelScope.launch { runCatching { api.saveData(data) }.onFailure { _error.emit(it.message) } } // Error handled and shown,Errors silently swallowed; data loss; user thinks action succeeded but it failed,Always handle exceptions in coroutines; use CoroutineExceptionHandler or runCatching,https://developer.android.com/kotlin/coroutines/coroutines-best-practices
|
|
103
|
+
Collecting Flow in Wrong Scope,Android,Coroutine,High,flow collect lifecycle repeatonlifecycle started launchwhenstrated leak,Collecting Flow in onCreate without lifecycle awareness; processes events when app backgrounded,lifecycleScope.launch { flow.collect { updateUI(it) } } // Collects even in background; wasted resources,lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { flow.collect { updateUI(it) } } },Processes events in background; battery drain; potential crashes updating invisible UI,Use repeatOnLifecycle(STARTED) or collectAsStateWithLifecycle() in Compose,https://developer.android.com/kotlin/flow/stateflow-and-sharedflow
|
|
104
|
+
Business Logic in UI,All,Architecture,Critical,business logic ui composable view activity fragment viewmodel separation,Business logic (validation calculation) directly in Composable/View,@Composable fun Checkout() { val total = items.sumOf { it.price * it.qty } * (1 - discount); if (total > 100) freeShipping = true },@Composable fun Checkout(viewModel: CheckoutViewModel) { val state by viewModel.state.collectAsStateWithLifecycle(); TotalText(state.formattedTotal) },Untestable; duplicated logic across platforms; UI test required for business rule verification,Extract all business logic to ViewModel or UseCase; UI only renders state,https://developer.android.com/topic/architecture/ui-layer
|
|
105
|
+
Exposing MutableState,Android,State,High,expose mutablestateflow mutablelivedata encapsulation internal state viewmodel,ViewModel exposing MutableStateFlow/MutableLiveData to UI; breaking encapsulation,val state = MutableStateFlow(UiState()) // UI can mutate ViewModel state directly,private val _state = MutableStateFlow(UiState()); val state: StateFlow<UiState> = _state.asStateFlow(),UI can modify ViewModel state bypassing business logic; unintended state mutations; untraceable bugs,Expose read-only StateFlow; keep MutableStateFlow private; mutate only through ViewModel functions,https://developer.android.com/kotlin/flow/stateflow-and-sharedflow
|
|
106
|
+
buildSrc Slowing Builds,Android,Build,Medium,buildsrc build logic slow invalidation convention plugin composite,Using buildSrc which invalidates all build caches on any change,// buildSrc/build.gradle.kts: any tiny change invalidates ENTIRE project cache,// build-logic/convention module: changes only invalidate convention plugin consumers; 80% faster incremental,buildSrc change = full project rebuild; no incremental; 5min rebuild from scratch,Move build logic to included build (build-logic) with composite builds,https://developer.android.com/build/migrate-to-catalogs
|
|
107
|
+
Unused Dependencies,All,Build,Medium,unused dependency dead code classpath bloat size apk ipa bundle,Dependencies added but never used; bloating app size and build time,// 50 dependencies; 20 unused; +8MB APK size; +30s build time; security surface increased,// ./gradlew buildHealth; // Identifies unused declared and used-undeclared dependencies,Add libraries 'just in case'; never remove; 50 deps but only 30 used,Zero unused dependencies,https://github.com/autonomousapps/dependency-analysis-android-gradle-plugin
|
|
108
|
+
No Loading Feedback,All,UX,High,loading feedback indicator spinner skeleton progress perceived performance,No loading indicator; user thinks app is frozen or broken,"// Button(onClick = { api.submit() }) { Text(""Post"") } // No loading state; user taps 5 times; 5 submissions","PostButton(onClick = { isLoading = true; viewModel.submit() } enabled = !isLoading) { if (isLoading) CircularProgressIndicator() else Text(""Post"") }",Blank screen during network call; no visual feedback; user taps button multiple times,Instant loading feedback,
|
|
109
|
+
Destructive Action Without Confirmation,All,UX,Medium,destructive action confirmation delete dialog undo irreversible,Delete/irreversible actions with no confirmation; accidental data loss,// IconButton(onClick = { dao.delete(item) }) // Immediately deletes; no confirmation; no undo; data lost,"AlertDialog(title = { Text(""Delete this item?"") } confirmButton = { TextButton(onClick = { delete() }) { Text(""Delete"" color = MaterialTheme.colorScheme.error) } })",Swipe-to-delete with no confirmation; tap 'Delete Account' instantly deletes,Confirm before destructive actions,
|
|
110
|
+
Ignoring Keyboard,All,UX,Medium,keyboard ime soft input adjustment scroll overlap textfield focus,Keyboard overlapping input fields; form fields hidden behind keyboard,// TextField behind keyboard; user types blind; can't see input or errors,// Scaffold(modifier = Modifier.imePadding()); // Or: BringIntoViewRequester for focused field,Form field hidden behind keyboard; user can't see what they're typing,Fields visible above keyboard,https://developer.android.com/develop/ui/compose/layouts/insets
|
|
111
|
+
Large SwiftUI View Body,iOS,SwiftUI,High,swiftui body large refactor extract subview performance,View body with 200+ lines; impossible to understand and slow to compile,// var body: some View { VStack { /* 400 lines of nested HStack VStack Group ForEach if-else */ } } // Unreadable; slow compile,struct OrderScreen: View { var body: some View { VStack { HeaderSection(); ItemsList(); TotalSection(); CheckoutButton() } } } // 4 lines,500-line body with nested conditionals; 30s build time for one file,< 30 lines per body,
|
|
112
|
+
Not Using @MainActor,iOS,Swift,Medium,mainactor swift concurrency sendable actor isolation ui thread,Updating UI from background thread causing crashes in Swift 6,// class ViewModel: ObservableObject { @Published var items: [Item] = []; func load() { Task { items = await api.fetch() } } } // Off-main update,@MainActor class HomeViewModel: ObservableObject { @Published var items: [Item] = []; func load() async { items = try await api.fetch() } },Update @Published properties from background thread; crash in Swift 6 strict concurrency,@MainActor for UI code,https://developer.apple.com/documentation/swift/mainactor
|
|
113
|
+
Not Using Keys in Lists,Flutter,Performance,Medium,flutter key widget list rebuild globalkey valuekey uniquekey identity,Missing keys in dynamic lists; incorrect widget recycling; state bugs,// ListView.builder(itemBuilder: (ctx i) => UserTile(user: users[i])) // No key; state mixup on reorder; wrong checkbox checked,ListView.builder(itemBuilder: (ctx i) => UserTile(key: ValueKey(users[i].id) user: users[i])),No keys; widgets recycled incorrectly; TextField in wrong row after reorder,Keys for stateful list items,https://api.flutter.dev/flutter/foundation/Key-class.html
|
|
114
|
+
Nested MediaQuery,Flutter,Performance,Medium,flutter mediaquery nested rebuild context unnecessary of,Using MediaQuery.of in deep widgets; unnecessary rebuilds on any media change,// MediaQuery.of(context).size.width; // Rebuilds on padding textScaleFactor orientation AND size changes,final width = MediaQuery.sizeOf(context).width; // Only notifies when size changes,MediaQuery.of(context) deep in tree; widget rebuilds on every keyboard show/hide,Use specific MediaQuery methods,https://api.flutter.dev/flutter/widgets/MediaQuery-class.html
|
|
115
|
+
Mismatched KSP and Kotlin Versions,Android,Build,Critical,ksp kotlin version mismatch build fail symbol processing,KSP version not matching Kotlin version causes build failures or cryptic errors,"ksp = ""1.9.24-1.0.20"" with kotlin = ""2.3.10"" // Version mismatch; build fails","ksp = ""2.3.4"" with kotlin = ""2.3.10""; or ksp = ""2.1.20-2.0.1"" with kotlin = ""2.1.20""",KSP must be compatible with Kotlin version; for Kotlin 2.2+ KSP uses decoupled versioning,Match KSP to Kotlin: Kotlin 2.3.10->KSP 2.3.4; Kotlin 2.1.20->KSP 2.1.20-2.0.1,https://github.com/google/ksp/releases
|
|
116
|
+
Mismatched AGP and Gradle Versions,Android,Build,Critical,agp gradle version incompatible plugin build fail android,Using AGP version that requires a newer Gradle than installed,AGP 9.0.1 with Gradle 8.x // AGP 9 requires Gradle 9.1+; AGP 8.13 requires Gradle 8.13,AGP 9.0.1 with Gradle 9.1+ or AGP 8.13.2 with Gradle 8.13,AGP will fail to sync or produce cryptic errors if Gradle version is too old,Check AGP release notes for minimum Gradle version before upgrading,https://developer.android.com/build/releases/gradle-plugin
|
|
117
|
+
Room with Incompatible Kotlin Version,Android,Build,Critical,room kotlin version incompatible jvm signature crash 2.6,Room 2.6.x with Kotlin 2.0+ causes unexpected jvm signature V error at compile time,"room = ""2.6.1"" with kotlin = ""2.1.20"" // Crashes: unexpected jvm signature V","room = ""2.8.4"" with kotlin = ""2.1.20"" // Room 2.7+ supports Kotlin 2.0+",Room 2.6.x uses old kotlinx-metadata-jvm incompatible with Kotlin 2.0+,Upgrade Room to 2.8.4+ when using Kotlin 2.0+,https://developer.android.com/jetpack/androidx/releases/room
|
|
118
|
+
Upgrading Single Dependency Without Checking Compatibility,Android,Build,High,version upgrade dependency compatibility matrix cascade breaking,Upgrading one library without checking cascade compatibility breaks build,"kotlin = ""2.3.10"" // upgraded but KSP Hilt AGP still on old versions",// AGP 9 track: agp=9.0.1 kotlin=2.3.10 ksp=2.3.4 hilt=2.59.1 room=2.8.4. Upgrade together.,Upgrading Kotlin alone breaks KSP; upgrading AGP to 9 requires Gradle 9.1+ and Hilt 2.59+,Always check AGP-Gradle KSP-Kotlin Room-Kotlin Hilt-AGP compatibility matrix before upgrading,https://developer.android.com/build/releases/gradle-plugin
|
|
119
|
+
Destructive Migration in Production,Android,Database,Critical,room migration destructive fallback production data loss wipe,Using fallbackToDestructiveMigration(true) in production builds causes all user data to be wiped when database schema changes,"Room.databaseBuilder(ctx AppDatabase::class.java ""app.db"").fallbackToDestructiveMigration(true).build() // In release build: user opens app after update and all data is gone","Room.databaseBuilder(ctx AppDatabase::class.java ""app.db"").addMigrations(MIGRATION_1_2 MIGRATION_2_3).build() // Proper migrations preserve data",Users lose all local data on app update; causes 1-star reviews and uninstalls,Use fallbackToDestructiveMigration(true) ONLY in debug builds; write proper Migration objects or use @AutoMigration for production,https://developer.android.com/training/data-storage/room/migrating-db-versions
|
|
120
|
+
No Room Migration Defined,Android,Database,Critical,room migration missing crash schema change version IllegalStateException,Incrementing Room @Database version without defining a migration causes IllegalStateException crash on app launch,"@Database(entities = [User::class] version = 2) // No migration from 1 to 2; app crashes: ""A migration from 1 to 2 was required but not found""",@Database(entities = [User::class] version = 2 autoMigrations = [@AutoMigration(from = 1 to = 2)]) // Or addMigrations(MIGRATION_1_2),App crashes for every existing user on update; no recovery without reinstall,Always define Migration or AutoMigration for every version increment,https://developer.android.com/training/data-storage/room/migrating-db-versions
|
|
121
|
+
Room Migration Without Testing,Android,Database,High,room migration test helper untested schema sql alter,Shipping Room migrations without testing them with MigrationTestHelper; migration SQL may silently corrupt data or crash,// Released Migration(1 2) with ALTER TABLE but never tested; typo in column name causes crash on user devices,"@get:Rule val helper = MigrationTestHelper(...); helper.createDatabase(""test"" 1).close(); helper.runMigrationsAndValidate(""test"" 2 true MIGRATION_1_2)",Untested migrations may crash or corrupt data for users who upgrade; cannot reproduce in dev if only testing fresh installs,Test every migration with MigrationTestHelper; test multi-step migration paths (1->2->3),https://developer.android.com/training/data-storage/room/migrating-db-versions#test
|
|
122
|
+
No Dark Mode Support,All,UI,Medium,dark mode night theme hardcoded color light only missing dark theme,App only supports light theme with hardcoded white backgrounds and dark text — looks broken in system dark mode,"Surface(color = Color.White) { Text(text = title, color = Color.Black) } // breaks in dark mode",Surface { Text(text = title) } // uses MaterialTheme.colorScheme automatically,Jarring UX when system dark mode enabled; white flash in dark environment,"Use MaterialTheme.colorScheme color roles (surface, onSurface, background) instead of hardcoded Color.White/Black",https://developer.android.com/develop/ui/compose/designsystems/material3#dark-theme
|