martes, 13 de febrero de 2018

Funciones - Clean code - Parte 2

Esta publicación es la continuación de la segunda parte del capítulo de Funciones de Clean Code (Robert C. Martin).

Listas de argumentos

En algunas ocasiones se pasará una lista de argumentos en una función. Si estos argumentos se tratan de la misma manera se podrán considerar como un único tipo de argumento de tipo lista.


Esta función es diádica puesto que los argumentos se tratan de la misma manera.


Esta regla se puede aplicar a funciones monádicas, diádicas o triádicas pero sería un error incluir más argumentos.

Verbos y palabras clave

La elección de nombres óptimos es, junto con el orden de los argumentos, la clave para transmitir la intención de la función. Las funciones monádicas deberían formar una tupla verbo / sustantivo. Por ejemplo «delete($filename)». El nombre del archivo «$filename» se está borrando.

Un nombre mejor sería «deleteFile($filename)» lo cual indica que un fichero (File) con un nombre de fichero «$filename» se va a borrar.

Sin efectos secundarios

Los efectos secundarios son acciones que se producen en la función y que no están descritas en el nombre. Esto rompe la norma que especifica que la función debe tener un solo cometido. Estos cambios pueden producirse en alguna variable de la función o el sistema y en otras ocasiones pueden derivar en extraños acoplamientos temporales y dependencias de orden.

La siguiente función valida un «password» y devuelve un valor «true» o «false».

El efecto secundario es iniciar una sesión. Esto crea acoplamientos temporales ya que sólo se podrá llamar a esta función cuando sea seguro iniciar una sesión pues de otra manera se podrían perder los datos de la sesión actual.

Argumentos de salida

Cuando un lector se encuentra con un argumento de salida tendrá que examinar el código dos veces para comprender qué está pasando, ya que los argumentos de una función se suelen usar normalmente como argumentos de entrada. Por esta razón se deben evitar los argumentos de salida.

Si una función tiene que cambiar el estado de algo debería cambiar el estado de su propio objeto.

Separación de consultas de comando

Las funciones deberían hacer algo o responder a algo pero no ambas cosas. Esto vulnera el principio que especifica que una función no debe tener más de un cometido.

La siguiente función asigna un valor y devuelve «true» o «false» dependiendo de si la asignación se ha hecho correctamente:


Esto puede llevar a encontrar situaciones como:


Desde el punto de vista de un lector, lo más posible es que, cuando llegue a esta parte del código, se pregunte si «set» se está utilizando como un verbo o como un adjetivo, si se intepreta como un verbo entonces se está asignando un valor y si se interpreta como un adjetivo entonces se está preguntando si la variable tiene un valor determinado.

Podría sustituir el nombre de la función por «checkAndSetAttribute» pero la función vulneraría el principio que especifica que las funciones deben tener un solo cometido.

La solución real es separar la consulta del comando para evitar ambigüedades:

Mejor excepciones que códigos de error

Devolver un código de error es una leve vulneración de la norma que especifica que cada función debe dedicarse a un solo cometido.

Además, surge el problema de tener que controlar el error en ese momento. Esto conlleva la creación de estructuras anidadas más complejas.


Si se usan excepciones se consigue evitar vulnerar dicho principio y tener que controlar el error en ese momento.


Extraer los bloques try / catch

Los bloques «try» y «catch» mezclan el código con la gestión de errores por lo que es recomendable extraer cada bloque de código con el fin de mejorar la legibilidad.


Al extraer el bloque de código en una función se da a entender que se realiza un proceso de borrado y un proceso de gestión de error, lo cual, facilita la compresión del código.

El control de errores es un cometido

Como las funciones deberían dedicarse a un solo cometido, cuando hay bloques «try» y «catch» en una función no debería haber nada más que dicho bloque «try» y «catch».

Imán de dependencias

Los códigos de error deberían estar definidos en un sólo lugar, ya sea una clase o una enumeración. En este caso vulnera el principio SRP, ya que tiene dos razones para cambiar, una si un código cambia y otra si hay que añadir un código nuevo. También vulnera el Open Close Principle ya que la clase no debería cambiar por añadir un nuevo código de error.

En el caso de usar excepciones se pueden crear nuevas clases que deriven de una excepción más general respetando de esta manera el Open Close Principle.

No repetirse

El principio Don’t repeat yourself se centra en reducir la duplicación de código mediante distintas abstracciones.

Si algunas partes de código están duplicadas se corre el riesgo de que no estén todas sincronizadas dando lugar a errores. Por lo que habría que abstraer ese código en una función o clase de manera que se encuentre en un único lugar dentro del sistema.

Programación estructurada

El programador holandés Dijkstra estableció que cada función o bloque debería tener una entrada y una salida por lo que cada función debería tener sólo una instrucción «return» y los bloques de tipo bucle no debería tener «break» ni «continue».

Una vez más, se trata de directrices más que de reglas fijas por lo que en ocasiones, la comprensión del código puede mejorar en funciones pequeñas aun presentando múltiples salidas o instrucciones «break» y «continue».

Cómo escribir este tipo de funciones

El primer paso es escribir una función que haga lo que tenga que hacer, es decir, que funcione. En esta primera fase las funciones son extensas, con distintos niveles de anidamiento, código duplicado, etc. También debería haber una cobertura de test que se adecue a las funcionalidades y verifique el comportamiento.

A partir de ese momento se debería empezar a modificar el código para mejorar su legibilidad, aplicando distintas estrategias como extraer métodos, renombrar variables y métodos, eliminar duplicados, extraer clases, etc.

Conclusión

Los buenos programadores piensan en los sistemas como historias que contar más que en programas que escribir. Ellos usan los recursos del lenguaje de programación para construir una historia más rica y más expresiva.

No hay comentarios:

Publicar un comentario