In Android projects — especially large-scale, multi-module, production apps — having a consistent review checklist reduces technical debt and keeps standards aligned across the team.
They are about maintainability, scalability, performance, and team trust.
Here’s a practical checklist I use for Android projects.
1. Architecture & Design
Good architecture makes the project survivable after years.
✔ Architecture Consistency
- Follows Clean Architecture / MVVM / MVI consistently
- Uni-directional data flow maintained
- Clear separation of UI / Domain / Data layers
✔ Business Logic Placement
- No business logic inside Activities or Fragments (or compose)
- ViewModels only handle UI-related logic
- Domain logic lives inside UseCases
✔ UseCases
- Single responsibility
- Small and focused
- No multi-purpose “God” use cases
✔ Dependency Injection
- Hilt / Dagger properly configured
- No manual dependency wiring
- No service locators hidden inside code
✔ Design Principles
- SOLID principles followed, along with others(DRY, KISS, GRASP, CQRS)
- Reuse of existing utility functions where appropriate
- No duplicated logic
- No broken unit tests
2. Kotlin & Language Usage
Kotlin gives powerful tools. Use them wisely.
✔ Immutability First
- Prefer val over var
- Immutable state where possible ### ✔ Kotlin Types
- Use data class for models
- sealed class for state representation
- enum when appropriate ### ✔ Null Safety
- Avoid nullable chains like ?.?.?.
- No use of !!
- Handle nulls explicitly and safely ### ✔ Extension & Scope Functions
- Extension functions improve readability (not dumping business logic)
- Scope functions (let, apply, run, also, with) used meaningfully
- No nested scope-function pyramids ### ✔ Data Structures
- Correct usage of List, MutableList, Map, Set
- Avoid unnecessary list copying
- Efficient transformations (map, filter, associate, etc.)
3. UI Layer (Compose / XML)
UI should be predictable and state-driven.
Jetpack Compose
- State hoisted properly
- UI is stateless where possible
- No side effects inside composables
- Use LaunchedEffect, SideEffect, remember, derivedStateOf correctly
- Awareness of recomposition behavior (use of key in list generate)
- Avoid unnecessary recompositions
XML / View System
- No heavy logic inside views
- Avoid deeply nested layouts
- ViewBinding enabled (no findViewById)
- No memory leaks from view references
4. State & Async Handling
Async mistakes are expensive in production.
✔ Coroutines & Flow
- Proper use of Flow, StateFlow, or LiveData
- No GlobalScope
- Cold vs hot stream usage is correct ### ✔ Dispatcher Usage
- IO for network/database
- Default for CPU work
- Main for UI ### ✔ Cancellation
- Jobs cancelled properly
- ViewModelScope used correctly ### ✔ Avoid Blocking
- No runBlocking in production
- No Thread.sleep()
- No heavy work on Main thread
5. Error Handling
Error handling defines production quality.
- Errors modeled explicitly (Result, Either, sealed classes)
- No silent catch {} blocks
- User-friendly error states exposed to UI
- Logs added meaningfully (no spam logging)
6. Performance
Performance issues hide in small mistakes.
- No heavy work on Main thread
- Avoid unnecessary recompositions
- Efficient list rendering (LazyColumn, DiffUtil)
- Pagination or lazy loading where needed
- No memory leaks (Context misuse, observers not cleared)
7. Testing
If it’s not tested, it’s fragile.
- Unit tests for UseCases
- Unit tests for ViewModels
- UI logic is state-driven and testable
- Mocks/Fakes used properly
- Descriptive test names
- Minimum coverage target followed (e.g., 80%)
- Test functions are maintainable and readable
8. Code Quality & Readability
Code should read like documentation.
- Small and focused functions
- Meaningful naming (no data, temp, obj)
- No commented-out dead code
- Consistent formatting (ktlint, detekt)
- No magic numbers — use constants
9. Security & Configuration
Small mistakes here can be costly.
- No API keys or secrets inside source code
- Tokens loaded from secure config
- Proguard / R8 rules reviewed
- Debug-only tools not leaking into release builds
- Do not pass secret user-data every layer or keep in memory
- Follow Security team guideline to avoid pentest defects/review comments
10. Git & PR Hygiene
Good PR hygiene reduces team friction.
- PR is small and focused
- Large tasks split into smaller subtasks
- Clear description of what and why
- Screenshots for UI changes
- Screen recording for flow (even with mock data)
- For defect fixes: include reproduction path and screen record
- Linked ticket/task for feature or bug
- No unrelated changes in the same PR
Final Thoughts
A good code review is not about nitpicking syntax.
It’s about protecting the future of the codebase.
When teams follow a structured checklist:
- Bugs decrease
- Performance improves
- Onboarding becomes easier
- Refactoring becomes safer (layer by layer)
- Trust increases
Code quality is not accidental. It is enforced — consistently.
Top comments (0)