intive Argentina Blog

Buenas prácticas para lograr clean code con Kotlin (parte II)

En nuestra primera entrega,¿Qué es “Clean Code”? Aprendiendo a mejorar tu código con Kotlin”, mencionamos dos prácticas importantísimas de esta metodología: utilizar funciones pequeñas y nombres significativos y, por otra parte, el uso de datos inmutables. En esta segunda entrega, como prometimos y, siempre a través de ejemplos prácticos, continuaremos analizando dos prácticas más, que completan nuestro listado de técnicas para lograr clean code.

1. Evitar establecer variables con valores nulos

El objetivo de esta práctica es minimizar la ausencia de las excepciones nulas. Afortunadamente, en Kotlin, las variables, por defecto, no pueden ser asignadas con valores nulos. Eso evita el problema con los NullPointerException.

No obstante, si se necesita trabajar con variables anulables, Kotlin provee de operadores para manejar de forma segura estas variables.

Para indicar que una variable puede ser nula se agrega al final de su declaración el operador «?»

El compilador lanzará un error porque no es seguro acceder a las propiedades de una variable que puede ser nula.

Como en Kotlin la sentencias if-else son consideradas expresiones, pueden ser parte de una asignación.

Pero en Kotlin no se considera una buena práctica realizar este tipo de controles. Es recomendable utilizar el operador de llamada segura, que es el mismo que se usa para marcar una variable como nula.

En la línea anterior, si la variable transaction no es nula, se asignará en la variable amount el valor del balance. En caso contrario, se asignará nulo.

Si se quiere asignar un valor defecto para evitar que el resultado sea nulo, se puede usar el operador elvis «?:».

Establece 0 si la variable transaction o balance, por alguna razón, son nulas.

Este operador puede usarse en situaciones muy complejas como las siguientes:

Si las variables user, bankAccount o balance fueran nulas se asigna un cero.

En lugar de asignar cero, lanza una excepción.

Kotlin cuenta con varias funciones de alcance que permiten operar con valores anulables. Por ejemplo, en vez de realizar la siguiente comprobación:

Se puede utilizar la función let, para evitar realizar comprobaciones nulas explicitas de la variable.

En ocasiones, se necesita declarar una variable antes de utilizarla. Esto puede implicar tener que declararla como nula y, posteriormente, realizar comprobaciones de llamadas seguras para verificar que realmente sea válida.

Podemos evitar este problema utilizando las expresiones lateinit y lazy para postergar la inicialización de un objeto hasta que en verdad lo amerite.

Por ejemplo:

Utilizando lateinit

Dentro de la clase GameBoard se define una variable scenes, la cual no es nula y no requiere de una asignación inicial.

Antes de usarse se debe asegurar que haya sido inicializada. De otra manera, el compilador lanzara la excepción UninitializedPropertyAccessException.

Utilizando lazy

La variable scenes de una instancia de GameBoard se inicializará la primera vez que se necesite, utilizando la lambda suministrada, que en este caso recibe la función initScenes.

2. Manejando los errores

El uso de excepciones es el enfoque más común para controlar los errores que pueden ocurrir en un programa.

Las excepciones presentan varios inconvenientes. Entre ellos es posible que vuelvan al código más engorroso de leer, debido al nivel de complejidad que agrega el bloque de código try-catch. Esto último puede hacerlo más confuso si se usan múltiples bloques consecutivos o anidados.

Si no se usan adecuadamente, esos múltiples bloques pueden generar un gran acoplamiento en los módulos de la aplicación y hacer más difícil rastrear el flujo de ejecución.

En el siguiente ejemplo se cuenta con el método de la clase Account, que realiza un retiro de dinero. Si el monto a retirar no cumple con las condiciones adecuadas, se lanza una excepción.

Para resolverlo podemos hacer uso de este método:

Esa es la manera tradicional de manejar los errores. Pero utilizando las sealed class de Kotlin se puede manejar el mismo problema orientándolo a la programación funcional.

Mediante las sealed class implementamos una clase que encapsule el resultado de la operación, pudiendo ser de un subtipo Success si el resultado fue exitoso o de un subtipo Error si hubo algún error.

La función withdraw devolvería una instancia de este objeto dependiendo del resultado.

Utilizando la expresión when manejamos ambos resultados:

Dado que todas las clases de resultados tienen una gran similitud, se podría emplear una clase genérica para representar cualquier tipo de operación.

Aquí podría ser Failure una clase base que permita modelar una jerarquía de errores.

Conclusión:

Siguiendo las buenas prácticas anteriores, resumamos:

  • Es preferible evitar el uso de variables que puedan ser nulas, debido a la complejidad adicional que pueden introducir al realizar su validación o comprobación.
  • Para el manejo adecuado de los errores, en lugar de devolver códigos de error, deberían usarse excepciones. De otra forma, se puede resolver usando un enfoque de la programación funcional.

Clean code, básicamente, es una filosofía de desarrollo de software que reúne una serie de guías o buenas prácticas para ayudarnos a escribir código de calidad, lo que nos convertirá en mejores desarrolladores, desarrolladores profesionales. Y ustedes, ¿qué opinan? ¿qué otra práctica recomiendan o implementan en su día a día?

Karlo Ismael Morales Oviedo

Karlo Ismael Morales Oviedo es desarrollador full-stack en intive Argentina desde marzo de 2018. Ingeniero en Informática egresado de la Universidad de Buenos Aires (UBA), Karlo además es técnico en control de máquinas y procesos industriales graduado del Servicio Nacional de Adiestramiento en Trabajo Industrial de Lima, Perú. Entre sus tantos hobbies, destacan: ir al cine, jugar al fútbol (hincha de River) y jugar videojuegos -en especial de acción o aventuras-. Siempre al día con las nuevas tecnologías que le interesan, en un futuro le gustaría realizar una especialización en Inteligencia Artificial.  

Deja un comentario