Clean Code на Kotlin: принципы и примеры для чистого кода

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Clean Code на Kotlin: принципы и примеры для чистого кода

Чистый код — это не просто модный термин, а фундаментальный навык профессионального разработчика. Когда вы пишете на Kotlin, современном и выразительном языке, принципы Clean Code становятся ещё более актуальными. Код, который легко читать, изменять и поддерживать, экономит часы дебаггинга и облегчает жизнь всей команде. В этой статье мы разберём ключевые принципы Clean Code на Kotlin с конкретными примерами, которые помогут вам писать элегантный и надёжный код.

1. Именование: говорите на языке предметной области

Правильное именование — основа чистого кода. Имена переменных, функций и классов должны сразу отвечать на вопросы "что это?" и "зачем это?". Избегайте однобуквенных сокращений и абстрактных названий вроде data или temp.

Плохой пример:

val d = mutableListOf<String>()
fun prc(u: User) {
    d.add(u.name)
    if (u.age > 18) println(u.name)
}

Хороший пример:

val registeredUserNames = mutableListOf<String>()

fun printAdultUserName(user: User) {
    registeredUserNames.add(user.name)
    if (user.isAdult()) {
        println(user.name)
    }
}

В хорошем примере сразу понятно, что делает функция и какие данные хранятся в списке. Используйте существительные для классов (UserRepository), глаголы для функций (processOrder) и булевы предикаты (isActive, hasPermission).

2. Функции: маленькие, однозадачные и без побочных эффектов

Одна из главных идей Clean Code — функция должна делать только одну вещь. Если функция превышает 15-20 строк, скорее всего, её нужно разбить. Kotlin с его функциями расширения и лямбдами отлично подходит для этого.

Пример: разбиваем сложную функцию

Допустим, у нас есть функция для обработки заказа:

fun processOrder(order: Order) {
    // Валидация
    if (order.items.isEmpty()) throw IllegalArgumentException("Order must have items")
    if (order.totalPrice < 0.0) throw IllegalArgumentException("Invalid price")
    
    // Расчёт скидки
    var finalPrice = order.totalPrice
    if (order.user.isPremium) {
        finalPrice *= 0.9
    }
    
    // Отправка уведомления
    emailService.send(order.user.email, "Your order is confirmed")
    smsService.send(order.user.phone, "Order #${order.id} confirmed")
}

Рефакторинг по принципам Clean Code:

fun processOrder(order: Order) {
    validateOrder(order)
    val finalPrice = calculateFinalPrice(order)
    sendOrderConfirmation(order, finalPrice)
}

private fun validateOrder(order: Order) {
    require(order.items.isNotEmpty()) { "Order must have items" }
    require(order.totalPrice >= 0.0) { "Invalid price" }
}

private fun calculateFinalPrice(order: Order): Double {
    return if (order.user.isPremium) order.totalPrice * 0.9 else order.totalPrice
}

private fun sendOrderConfirmation(order: Order, finalPrice: Double) {
    val message = "Order #${order.id} confirmed. Total: $finalPrice"
    notificationService.notifyUser(order.user, message)
}

Теперь каждая функция отвечает за одну задачу, их легко тестировать и переиспользовать.

3. Null Safety: используйте возможности Kotlin

Одна из главных фишек Kotlin — null safety. Clean Code на Kotlin подразумевает полное избавление от null там, где это возможно. Избегайте использования !! (not-null assertion) — это почти всегда признак плохого дизайна.

Плохой пример:

fun getUserName(userId: String): String {
    val user = userRepository.findById(userId)!!
    return user.name!!
}

Хороший пример:

fun getUserName(userId: String): String? {
    val user = userRepository.findById(userId) ?: return null
    return user.name ?: "Unknown"
}

Используйте ?. (safe call), ?: (elvis operator) и let/also для безопасной работы с nullable-типами. Если значение не может быть null, используйте ненулевые типы.

data class Address(val city: String, val street: String?)

fun printAddress(address: Address) {
    println("City: ${address.city}")
    address.street?.let { println("Street: $it") } ?: println("Street not specified")
}

4. SOLID и функциональный стиль: комбинируйте подходы

Принципы SOLID отлично работают в Kotlin. Особенно важны Single Responsibility и Dependency Inversion. Kotlin также поощряет функциональный стиль с неизменяемыми данными (val) и чистыми функциями.

Пример: Dependency Injection через конструктор

class OrderService(
    private val paymentGateway: PaymentGateway,
    private val notificationService: NotificationService
) {
    fun placeOrder(order: Order): OrderResult {
        val paymentResult = paymentGateway.charge(order.totalPrice, order.user)
        if (paymentResult.isSuccess) {
            notificationService.sendOrderConfirmation(order)
            return OrderResult.Success(order)
        }
        return OrderResult.Failed("Payment declined")
    }
}

Здесь класс зависит от абстракций (интерфейсов), а не от конкретных реализаций. Это упрощает тестирование и замену компонентов.

Используйте неизменяемые коллекции и data class

data class Product(val id: String, val name: String, val price: Double)

fun applyDiscount(products: List<Product>, discount: Double): List<Product> {
    return products.map { product ->
        product.copy(price = product.price * (1 - discount))
    }
}

data class автоматически предоставляет equals(), hashCode(), toString() и copy(), что делает код чище. Функция applyDiscount не изменяет исходный список, а возвращает новый — это принцип иммутабельности.

Заключение

Clean Code на Kotlin — это не набор жёстких правил, а философия, которая делает вашу работу проще и приятнее. Начните с малого: давайте осмысленные имена, разбивайте большие функции, используйте null safety по назначению и следуйте SOLID. Со временем чистый код войдёт в привычку, и вы заметите, как снижается количество багов и упрощается рефакторинг.

Помните

Блоги

Рекомендаций по книгам