Clean Code на Kotlin: принципы и примеры для чистого кода
Clean Code is not just a buzzword, but a fundamental skill for a professional developer. When you write in Kotlin, a modern and expressive language, the principles of Clean Code become even more relevant. Code that is easy to read, modify, and maintain saves hours of debugging and makes life easier for the entire team. In this article, we will break down the key principles of Clean Code in Kotlin with concrete examples that will help you write elegant and reliable code.
1. Naming: speak the language of the domain
Proper naming is the foundation of clean code. Names of variables, functions, and classes should immediately answer the questions "what is this?" and "what is it for?". Avoid single-letter abbreviations and abstract names like data or temp.
Bad example:
val d = mutableListOf<String>()fun prc(u: User) { d.add(u.name) if (u.age > 18) println(u.name)}Good example:
val registeredUserNames = mutableListOf<String>()
fun printAdultUserName(user: User) { registeredUserNames.add(user.name) if (user.isAdult()) { println(user.name) }}In the good example, it is immediately clear what the function does and what data is stored in the list. Use nouns for classes (UserRepository), verbs for functions (processOrder), and boolean predicates (isActive, hasPermission).
2. Functions: small, single-purpose, and without side effects
One of the main ideas of Clean Code is that a function should do only one thing. If a function exceeds 15-20 lines, it most likely needs to be broken down. Kotlin, with its extension functions and lambdas, is perfect for this.
Example: breaking down a complex function
Suppose we have a function for processing an order:
fun processOrder(order: Order) { // Validation if (order.items.isEmpty()) throw IllegalArgumentException("Order must have items") if (order.totalPrice < 0.0) throw IllegalArgumentException("Invalid price") // Discount calculation var finalPrice = order.totalPrice if (order.user.isPremium) { finalPrice *= 0.9 } // Sending notification emailService.send(order.user.email, "Your order is confirmed") smsService.send(order.user.phone, "Order #${order.id} confirmed")}Refactoring according to Clean Code principles:
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)}Now each function is responsible for one task, they are easy to test and reuse.
3. Null Safety: use Kotlin's capabilities
One of the main features of Kotlin is null safety. Clean Code in Kotlin implies completely eliminating null where possible. Avoid using !! (not-null assertion) — it is almost always a sign of bad design.
Bad example:
fun getUserName(userId: String): String { val user = userRepository.findById(userId)!! return user.name!!}Good example:
fun getUserName(userId: String): String? { val user = userRepository.findById(userId) ?: return null return user.name}```