Clean Code en Kotlin: principios y ejemplos en la práctica
El código limpio (Clean Code) no es solo un término de moda, sino una habilidad fundamental para cualquier desarrollador profesional. En el contexto de Kotlin, un lenguaje moderno y conciso, los principios del código limpio adquieren una importancia especial. Kotlin permite escribir código expresivo, pero sin disciplina es fácil crear una arquitectura confusa. En este artículo, analizaremos los principios clave de Clean Code con ejemplos en Kotlin que te ayudarán a escribir código comprensible para tus colegas y para ti mismo dentro de seis meses.
1. Nombres significativos: la clave para un código legible
La correcta nomenclatura es el primer paso hacia un código limpio. Los nombres de variables, funciones y clases deben responder a las preguntas "¿por qué?", "¿qué?" y "¿cómo?". Kotlin ofrece herramientas potentes para ello.
Ejemplo malo:
fun calc(a: Int, b: Int): Int { val c = a + b * 2 return c}Ejemplo bueno (Clean Code):
fun calculateDiscountedPrice(basePrice: Int, discountPercent: Int): Int { val discountAmount = basePrice * discountPercent / 100 return basePrice - discountAmount}En el buen ejemplo, cada nombre se explica por sí mismo. calculateDiscountedPrice es un verbo que describe la acción. basePrice y discountPercent son sustantivos que transmiten con precisión la esencia de los datos. Kotlin admite argumentos con nombre, lo que hace que las llamadas a funciones sean aún más transparentes:
val finalPrice = calculateDiscountedPrice(basePrice = 1000, discountPercent = 20)Reglas importantes:
- Evite nombres de una sola letra (excepto para índices de bucles).
- Use
camelCasepara variables y funciones. - Para valores booleanos, use prefijos como
is,has,can(por ejemplo,isActive,hasPermission).
2. Funciones: una función, una tarea
El principio de responsabilidad única (Single Responsibility Principle) no solo se aplica a las clases, sino también a las funciones. Una función debe hacer una sola cosa y hacerla bien. Kotlin, con sus capacidades funcionales, facilita esta práctica.
Ejemplo malo (la función hace demasiado):
fun processUser(userId: String) { val user = database.findUser(userId) if (user != null) { user.name = user.name.uppercase() database.updateUser(user) sendEmail(user.email, "Welcome!") }}Ejemplo bueno (división en funciones pequeñas):
fun processUser(userId: String) { val user = findUserOrThrow(userId) val updatedUser = user.apply { name = name.uppercase() } updateUserInDatabase(updatedUser) sendWelcomeEmail(updatedUser.email)}
private fun findUserOrThrow(userId: String): User { return database.findUser(userId) ?: throw IllegalArgumentException("User not found")}
private fun updateUserInDatabase(user: User) { database.updateUser(user)}
private fun sendWelcomeEmail(email: String) { sendEmail(email, "Welcome!")}Ahora cada función se encarga de un paso lógico. Esto facilita las pruebas, la depuración y la reutilización del código. Las funciones de Kotlin pueden ser locales (anidadas), lo que permite encapsular la lógica sin crear clases adicionales.
3. Trabajo con tipos nullable y manejo elegante de errores
Clean Code implica una gestión explícita de la incertidumbre. Kotlin introduce tipos nullable (?) y potentes operadores para trabajar con ellos de forma segura. El uso de !! (aserción no nula) es una señal de mal código. En su lugar, aplique llamadas seguras y el operador Elvis.
Ejemplo malo (riesgo de NPE):
fun getCity