返回 Skill 列表
extension
分类: 开发与工程无需 API Key

android-conventions

定义项目的Android/Kotlin编码规范。包括命名规则、禁止模式、首选实践和代码风格指南。在编写代码时使用以确保一致性。当用户提到:命名、约定、编码规则、风格指南、禁止模式、推荐模式、名称规则、代码风格、检查约定、命名规则时使用。

person作者: jakexiaohubgithub

Android Coding Conventions

프로젝트 코딩 컨벤션 및 스타일 가이드입니다.

Naming Conventions

Classes and Interfaces

| Type | Pattern | Example | |------|---------|---------| | UseCase | {Action}{Subject}UseCase | GetLottoResultUseCase | | Repository Interface | {Subject}Repository | LottoRepository | | Repository Impl | {Subject}RepositoryImpl | LottoRepositoryImpl | | ViewModel | {Feature}ViewModel | HomeViewModel | | Contract | {Feature}Contract | HomeContract | | Screen | {Feature}Screen | HomeScreen | | Content | {Feature}Content | HomeContent | | DataSource | {Subject}{Type}DataSource | LottoRemoteDataSource | | DTO | {Subject}Dto | LottoDto | | Entity | {Subject}Entity | LottoEntity |

Functions

| Type | Pattern | Example | |------|---------|---------| | UseCase invoke | operator fun invoke() | suspend operator fun invoke(round: Int) | | Event handler | on{Action} | onRefresh(), onItemClick() | | Private helper | {action}{Subject} | loadData(), updateState() | | Mapper | to{Target}() | toEntity(), toDomain() |

Variables

| Type | Pattern | Example | |------|---------|---------| | StateFlow | _uiState / uiState | Private mutable / Public immutable | | Channel | _effect / effect | Private / Public | | Boolean | is{State}, has{Thing} | isLoading, hasError | | Collection | Plural nouns | items, results, numbers |

Modules

feature:{feature-name}    # feature:home, feature:qrscan
core:{core-name}          # core:domain, core:data, core:network

Forbidden Patterns

🚫 절대 사용 금지

| Pattern | Reason | Alternative | |---------|--------|-------------| | LiveData | Deprecated pattern | StateFlow | | AsyncTask | Deprecated | Coroutines | | GlobalScope | Memory leak risk | viewModelScope | | runBlocking (production) | Blocks thread | suspend + coroutines | | findViewById | Old pattern | View Binding or Compose | | XML layouts (new screens) | Migration to Compose | Jetpack Compose | | Mutable collections (public) | Immutability violation | Immutable collections |

Code Examples

// ❌ Don't
val items = mutableListOf<Item>()  // Public mutable
GlobalScope.launch { ... }
runBlocking { ... }

// ✅ Do
val items: List<Item> get() = _items.toList()  // Immutable copy
viewModelScope.launch { ... }
suspend fun doSomething() { ... }

Preferred Patterns

✅ 권장 패턴

| Pattern | Usage | |---------|-------| | invoke operator | UseCase entry point | | Result<T> | Error handling | | State hoisting | Compose state management | | Immutable data class | Domain models | | suspend functions | One-shot operations | | Flow | Data streams | | Modifier first optional | Composable parameters |

Code Examples

// ✅ UseCase with invoke
class GetDataUseCase @Inject constructor(...) {
    suspend operator fun invoke(id: String): Result<Data> = ...
}

// ✅ Result type for errors
suspend fun getData(): Result<Data> = runCatching {
    repository.fetchData()
}

// ✅ Immutable data class
data class LottoResult(
    val round: Int,
    val numbers: List<Int>,  // List is immutable interface
    val bonusNumber: Int
)

// ✅ Modifier as first optional parameter
@Composable
fun MyComponent(
    text: String,                    // Required
    modifier: Modifier = Modifier,   // First optional
    enabled: Boolean = true          // Other optionals
)

Architecture Rules

Layer Dependencies

✅ Allowed:
Presentation → Domain
Data → Domain

❌ Forbidden:
Domain → Data
Domain → Presentation
Presentation → Data (direct)

Module Dependencies

✅ Allowed:
feature:* → core:domain
feature:* → core:di
core:data → core:domain
core:data → core:network
core:data → core:database

❌ Forbidden:
core:domain → core:data
core:domain → core:network
feature:home → feature:qrscan (direct)

Code Style

Imports

// ✅ Explicit imports (preferred)
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.MutableStateFlow

// ⚠️ Star imports (avoid when possible)
import kotlinx.coroutines.flow.*

Formatting

// ✅ Parameter on new line when many
fun createViewModel(
    useCase1: UseCase1,
    useCase2: UseCase2,
    repository: Repository
): ViewModel

// ✅ Chain calls vertically
repository.getData()
    .map { it.toDomain() }
    .catch { emit(emptyList()) }
    .collect { ... }

Comments

// ✅ KDoc for public APIs
/**
 * Fetches lotto result for the given round.
 *
 * @param round The round number to fetch
 * @return Result containing LottoResult or error
 */
suspend fun getLottoResult(round: Int): Result<LottoResult>

// ✅ Explain WHY, not WHAT
// Cache for 5 minutes to reduce API calls during rapid navigation
private val cache = CacheBuilder.newBuilder()
    .expireAfterWrite(5, TimeUnit.MINUTES)
    .build()

// ❌ Don't explain obvious code
// Increment counter by 1
counter++

Korean Market Specifics

Localization Formats

| Type | Format | Example | |------|--------|---------| | Date | YYYY년 MM월 DD일 | 2024년 01월 15일 | | Time | 오전/오후 HH:MM | 오후 08:45 | | Currency | ₩{amount:,} | ₩1,000,000,000 |

Accessibility

  • Korean TTS pronunciation 고려
  • 문장 길이 ≤ 30자 권장
  • 명확한 동작 설명 ("로또 결과 새로고침")

File Organization

feature/home/
├── HomeScreen.kt           # Screen composable
├── HomeViewModel.kt        # ViewModel
├── HomeContract.kt         # UiState, Event, Effect
├── navigation/
│   └── HomeNavigation.kt   # Navigation setup
└── components/
    ├── LottoResultCard.kt  # Reusable component
    └── NumberBall.kt       # Reusable component