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.
No hay comentarios:
Publicar un comentario