← Назад к вопросам

Как писать качественный common code в Kotlin Multiplatform

2.4 Senior🔥 101 комментариев
#Kotlin основы#Архитектура и паттерны#Многомодульность

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Подход к написанию качественного common-кода в KMM

Качественный common-код в Kotlin Multiplatform (KMP) — это основа успешной кросс-платформенной разработки. Вот ключевые принципы и практики:

Архитектурные принципы

Многоуровневая архитектура — разделяйте код на слои:

// Domain-слой (полностью common)
interface UserRepository {
    suspend fun getUser(id: String): User
}

// Data-слой с expect/actual для платформенных реализаций
expect class DatabaseDriverFactory {
    fun createDriver(): SqlDriver
}

Принцип инверсии зависимостей — зависьте от абстракций, а не от реализаций:

// В common-коде
expect interface BiometricAuthenticator {
    suspend fun authenticate(): Boolean
}

// В платформенных модулях
actual class AndroidBiometricAuthenticator : BiometricAuthenticator {
    actual override suspend fun authenticate(): Boolean {
        // Android-реализация
    }
}

Паттерны проектирования

  1. Используйте корутины для асинхронных операций:
class NetworkService(
    private val httpClient: HttpClient
) {
    suspend fun fetchData(): Result<Data> = runCatching {
        httpClient.get("https://api.example.com/data")
    }
}
  1. Применяйте sealed-классы/интерфейсы для моделирования состояний:
sealed interface Result<out T> {
    data class Success<T>(val data: T) : Result<T>
    data class Error(val exception: Throwable) : Result<Nothing>
    object Loading : Result<Nothing>
}

Организация кода

Структура модулей:

shared/
├── commonMain/          # Общая бизнес-логика
├── androidMain/         # Android-специфичные реализации
├── iosMain/            # iOS-специфичные реализации
└── desktopMain/        # Desktop-реализации (если нужно)

Правила именования:

  • expect/actual для платформенно-зависимого кода
  • Суффиксы Common, Shared для общих компонентов
  • Четкое разделение по пакетам: domain, data, presentation

Тестирование common-кода

Unit-тесты в commonTest:

// commonTest/kotlin
class CalculatorTest {
    @Test
    fun testAddition() {
        val calculator = Calculator()
        assertEquals(5, calculator.add(2, 3))
    }
}

Mocking платформенных зависимостей:

class TestFileSystem : FileSystem {
    override fun readFile(path: String): String = "test content"
    override fun writeFile(path: String, content: String) {}
}

Оптимизация и производительность

  1. Минимизируйте expect/actual declarations — выносите максимум логики в common
  2. Используйте inline-классы для type-safe примитивов:
@JvmInline
value class UserId(val value: String)

@JvmInline
value class Email(val value: String)
// Компилятор не создает дополнительных объектов
  1. Оптимизируйте сериализацию с помощью kotlinx.serialization:
@Serializable
data class ApiResponse<T>(
    @SerialName("data")
    val data: T,
    @SerialName("status")
    val status: String
)

Обработка ошибок

Единая система ошибок:

sealed class AppError : Throwable() {
    data class NetworkError(val code: Int) : AppError()
    data class ValidationError(val field: String) : AppError()
    object UnknownError : AppError()
}

// Общий обработчик
suspend fun <T> safeCall(block: suspend () -> T): Result<T> {
    return try {
        Result.success(block())
    } catch (e: AppError) {
        Result.failure(e)
    }
}

Платформенно-зависимый код

Изолируйте платформенные зависимости через интерфейсы:

// Common
expect class PlatformLogger {
    fun logDebug(message: String)
    fun logError(message: String, throwable: Throwable)
}

// Android
actual class PlatformLogger {
    actual fun logDebug(message: String) {
        Log.d("App", message)
    }
    // ... остальные методы
}

Миграция и поддержка

  1. Постепенная миграция — начинайте с небольших модулей
  2. Совместимость с существующим кодом — используйте адаптеры
  3. Документация — документируйте ограничения и особенности common-кода

Инструменты и библиотеки

Обязательный набор:

  • kotlinx.coroutines — асинхронность
  • kotlinx.serialization — сериализация
  • Koin или Kodein — DI (если нужно)
  • kotlinx-datetime — работа с датами

Качество кода:

  • Detekt для статического анализа
  • Dokka для документации
  • Gradle version catalog для управления зависимостями

Ключевой принцип: пишите common-код так, будто это обычный Kotlin-модуль, изолируя платформенно-зависимые части через четкие интерфейсы. Тестируемость, поддерживаемость и четкое разделение ответственности — залог успешного мультиплатформенного проекта.