projectrules.ai

jetpack-compose

androiduistate-managementperformancearchitecture

Description

Enforces Jetpack Compose best practices for code organization, performance, and maintainability. This rule provides guidelines for writing efficient and idiomatic Compose code.

Globs

**/*.kt
---
description: Enforces Jetpack Compose best practices for code organization, performance, and maintainability. This rule provides guidelines for writing efficient and idiomatic Compose code.
globs: **/*.kt
---

- **Code Organization and Structure**
  - **Directory Structure:**
    - Organize composables by feature or screen. Each feature should have its own directory.
    - Example:

      app/
        src/
          main/
            java/
              com/example/app/
                feature_a/
                  FeatureAScreen.kt
                  FeatureAViewModel.kt
                  components/
                    FeatureAButton.kt
                    FeatureATextField.kt
                feature_b/
                  ...

  - **File Naming Conventions:**
    - Use PascalCase for composable function names (e.g., `MyComposable`).
    - Use descriptive names that clearly indicate the composable's purpose.
    - Name files after the primary composable they contain (e.g., `MyComposable.kt`).
  - **Module Organization:**
    - Separate UI code (composables) from business logic (ViewModels, repositories).  Use modules to enforce this separation.
    - Consider using feature modules for large applications to improve build times and maintainability.
  - **Component Architecture:**
    - Design composables as small, reusable components.
    - Follow the single responsibility principle: each composable should have a single, well-defined purpose.
    - Use a hierarchical component structure to build complex UIs from smaller, simpler components.
  - **Code Splitting Strategies:**
    - Break down large composables into smaller, more manageable parts.
    - Use inline functions judiciously.  Overuse can hurt performance.
    - Consider using `derivedStateOf` to only recompose when necessary based on derived state.

- **Common Patterns and Anti-patterns**
  - **Design Patterns:**
    - **State Hoisting:** Move state as high as possible in the composable tree to maximize reusability and testability.  Pass state down as parameters.
    - **Unidirectional Data Flow:**  Data flows down the composable tree, and events flow up. This makes it easier to reason about the state of the UI.
    - **Composition Local:** Use sparingly to provide implicit dependencies to composables.  Avoid overusing as it can make dependencies less explicit.
    - **ViewModel:** Use a ViewModel to hold UI state and handle business logic. This separates the UI from the data layer and makes the UI easier to test.
  - **Recommended Approaches:**
    - Use `remember` to cache expensive calculations and avoid unnecessary recompositions.
    - Use `mutableStateOf` or `rememberSaveable` to store UI state.
    - Use `LaunchedEffect` or `rememberCoroutineScope` for side effects (e.g., network requests, database access).
    - Use `animate*AsState` functions for smooth animations.
  - **Anti-patterns and Code Smells:**
    - **Reading State from Too High a Scope:** Avoid reading state too high in the composition tree, as this can cause unnecessary recompositions.
    - **Mutable State in Composables without remember:** If you're not using remember, every recomposition will create a new state, leading to unexpected behavior.
    - **Long Composable Functions:** Break large composables into smaller, more manageable parts.
    - **Hardcoded Values:** Avoid hardcoding values directly in composables. Use resources or constants instead.
    - **Unnecessary Recomposition:**  Profile your code to identify and eliminate unnecessary recompositions.  Tools like the Layout Inspector can help.
  - **State Management Best Practices:**
    - Choose the right state management solution for your needs (e.g., `remember`, `mutableStateOf`, `StateFlow`, `LiveData`).
    - Keep state as immutable as possible.  Use `copy()` to create new state objects instead of modifying existing ones.
    - Use `derivedStateOf` to derive state from other state objects.
  - **Error Handling Patterns:**
    - Use `try-catch` blocks to handle exceptions in composables.
    - Display error messages to the user in a clear and informative way.
    - Use a central error handling mechanism to log errors and prevent crashes.  Consider using a `Snackbar` or a dedicated error display composable.

- **Performance Considerations**
  - **Optimization Techniques:**
    - **`remember`:** Cache expensive calculations and resources.
    - **`derivedStateOf`:** Only recompose when derived state changes.
    - **`SnapshotFlow`:** Collect data from mutable state without recomposing.
    - **`CompositionLocalProvider`:** Provides an alternative way to pass data if recomposition is a bottleneck.  Use with caution as it can make dependencies implicit.
    - **`Skippable Composable Functions`:** Compose Compiler performs the best optimization for functions that are skippable. To allow skipping, a composable must meet the following criteria:
      - All parameters passed to the composable are stable.
      - The composable's result is the same given the same parameters.
    - **Inline Functions (with care):** Useful for small functions but can increase bytecode size if overused.
  - **Memory Management:**
    - Avoid creating large objects in composables.
    - Release resources when they are no longer needed.
    - Use `WeakReference` to avoid memory leaks.
  - **Rendering Optimization:**
    - Use `Modifier.drawBehind` and `Modifier.drawWithContent` for custom drawing.
    - Avoid overdraw by using `Modifier.clip` and `Modifier.background`.
    - Use `Spacer` to control layout instead of adding padding to multiple elements.
  - **Bundle Size Optimization:**
    - Use R8 to shrink and obfuscate your code.
    - Remove unused resources.
    - Use dynamic feature modules to deliver features on demand.
  - **Lazy Loading Strategies:**
    - Use `LazyColumn` and `LazyRow` to display large lists of data.
    - Use `rememberLazyListState` to persist the scroll position of lazy lists.

- **Security Best Practices**
  - **Common Vulnerabilities:**
    - **Input Validation:**  Sanitize user input to prevent injection attacks.
    - **Data Protection:**  Encrypt sensitive data at rest and in transit.
    - **Secure API Communication:**  Use HTTPS to encrypt communication between the app and the server.
  - **Input Validation:**
    - Validate user input to prevent injection attacks and other security vulnerabilities.
    - Use regular expressions or other validation techniques to ensure that input is in the expected format.
  - **Authentication and Authorization Patterns:**
    - Use a secure authentication and authorization mechanism to protect sensitive data and functionality.
    - Use OAuth 2.0 or OpenID Connect for authentication.
    - Use role-based access control (RBAC) for authorization.
  - **Data Protection Strategies:**
    - Encrypt sensitive data at rest and in transit.
    - Use a strong encryption algorithm.
    - Store encryption keys securely.
  - **Secure API Communication:**
    - Use HTTPS to encrypt communication between the app and the server.
    - Use certificate pinning to prevent man-in-the-middle attacks.

- **Testing Approaches**
  - **Unit Testing Strategies:**
    - Test composables in isolation using `ComposeTestRule`.
    - Verify that composables render correctly and handle user input as expected.
    - Use `composeTestRule.setContent { ... }` to set the content of the test.
    - Use `composeTestRule.onNodeWithText("...").performClick()` to simulate user interactions.
  - **Integration Testing:**
    - Test the interaction between different composables and ViewModels.
    - Use `Hilt` or `Koin` to inject dependencies into tests.
  - **End-to-end Testing:**
    - Test the entire application flow from the user's perspective.
    - Use `UIAutomator` or `Espresso` for end-to-end testing.
  - **Test Organization:**
    - Organize tests by feature or screen.
    - Create a separate test module for each feature module.
  - **Mocking and Stubbing:**
    - Use `Mockito` or `Mockk` to mock dependencies in unit tests.
    - Use `Fake` implementations for integration tests.

- **Common Pitfalls and Gotchas**
  - **Frequent Mistakes:**
    - Forgetting to use `remember` for state.
    - Reading state from too high a scope.
    - Not handling errors properly.
    - Not optimizing performance.
  - **Edge Cases:**
    - Handling different screen sizes and orientations.
    - Handling different locales and languages.
    - Handling different accessibility requirements.
  - **Version-Specific Issues:**
    - Be aware of breaking changes in new versions of Jetpack Compose.
    - Use the latest version of Jetpack Compose to take advantage of new features and bug fixes.
  - **Compatibility Concerns:**
    - Ensure that your app is compatible with different Android versions.
    - Use Jetpack Compose libraries that are compatible with your target Android version.
  - **Debugging Strategies:**
    - Use the Android Studio debugger to step through your code and inspect variables.
    - Use the Layout Inspector to inspect the composable tree and identify performance bottlenecks.
    - Use the Profiler to measure the performance of your app.

- **Tooling and Environment**
  - **Recommended Development Tools:**
    - Android Studio
    - Kotlin Compiler
    - Jetpack Compose Libraries
  - **Build Configuration:**
    - Use Gradle to manage dependencies and build your app.
    - Configure the Kotlin compiler to use the latest version of Jetpack Compose.
  - **Linting and Formatting:**
    - Use `ktlint` or `detekt` to enforce code style guidelines.
    - Use `Prettier` to format your code automatically.
  - **Deployment Best Practices:**
    - Use the Google Play Store to distribute your app.
    - Use a staged rollout to gradually release your app to users.
  - **CI/CD Integration:**
    - Use a CI/CD system to automate the build, test, and deployment process.
    - Use `GitHub Actions` or `CircleCI` for CI/CD.
jetpack-compose