sábado, 3 de diciembre de 2016

Clean Code Capítulo 3 Funciones


Al crear software debemos proporcionar mecanismos para llevar a cabo diferentes acciones, por esto aparecen las Funciones. En Clean Code, se hace énfasis en lo importante que es crear cada función para hacer una cosa, que vayan contando una historia y que cada una lleve a la siguiente. Si observamos secciones en funciones (por ejemplo declaraciones, inicializaciones y filtros), es una clara señal que la función hace más de una cosa, otro caso es cuando una función hace lo que dice que hace en su nombre, pero hace algo extra (se está incumpliendo la regla de hacer una cosa) generando un efecto secundario inesperado, siempre recordemos que las funciones son sin efecto secundarios, por lo tanto, si es necesario, se debe pensar en refactorizar. Una función debe responder a algo o hacer algo, pero no las dos cosas, de ahí que surge lseparación de consultas de comando, el autor lo expresa de la siguiente manera "Su función debe cambiar el estado de un objeto o devolver información sobre el mismo, pero ambas operaciones causan confusión".

Al darles nombre no olvidemos el capítulo nombres con consentido, por esto se debe usar nombre descriptivos, que revelen la verdadera intención o acción de la función, una recomendación es utilizar verbos y palabras claves como por ejemplo writeField(name). write (Verbo), Field (Palabra Clave).

Cada función debe ser de tamaño reducido, ¿Cuántas líneas? no sabría decirte con exactitud, pero si nos basamos en el libro, este nos recomienda que tengan una longitud aproximada de 20 líneas, en estas líneas hay que prestar mucha atención a los bloques y sangrados. Cuando hablo de bloques hago referencia a fragmentos de códigos dentro de if, else, for y similares, en este caso la recomendación es que su longitud sea de una sola línea (lo más probable es que se invoque a otra función); en cuanto al nivel de sangrado no debe ser mayor a dos, ayudando a que haya un nivel de abstracción por función haciendo más fácil de comprenderla, con lo anterior se puede leer el código de arriba a abajo (la regla descendente). Esta regla consiste en posicionar las funciones por nivel de abstracción, como lo explican en Clean Code "Queremos que tras todas las funciones aparezcan las del siguiente nivel de abstracción para poder leer el programa, descendiendo un nivel de abstracción por vez mientras leemos la lista de funciones".

Otra parte clave en las funciones son sus argumentos, cuyo número ideal es cero, posteriormente uno (mónadico) y dos (diádico); se debe evitar las funciones de tres argumentos (triádico), las de más de tres argumentos (poliádico) deben tener una motivo especial. Las formas monádicas habituales son tanto para preguntar sobre el argumento o para transformar el argumento en otra cosa, un caso poco habitual es para eventos, en este caso las funciones por lo general no devuelven nada. En este punto el autor desaconseja utilizar argumentos de indicador (Pasar un booleano a una función) ya que de una forma u otra está indicando que la función hace más de una cosa. Para las funciones diádicas se debe propender que los argumentos sigan y tengan un orden natural, cuando estos carecen de dicho orden debe el programador utilizar los mecanismos necesarios para evitarlas. Cuando una función requiere dos o más argumentos se suele utilizar Objetos Como argumentos, pero esto no es una trampa, pues suele suceder que las variables antes pasadas como argumentos pertenezcan a un concepto más grande. Los nombres de los argumentos deben ser claros y acordes al contexto.

Algunas funciones tienen argumentos de salida, es decir, ver argumentos que en vez de ser entrada son salidas, estos argumentos deben evitarse.

El manejo de errores en una función en muchos casos se hace por medio de códigos de error, que suelen estar en una clase o varias lo que va creando alto acoplamiento y cuando surge un nuevo tipo de error, es donde viene los dolores de cabeza, por esto es mejor emplear excepciones que devolver código de error. Al utilizar excepciones es inevitable utilizar Try/Catch esto empieza a generar estructuras anidadas por eso es una buena práctica extraer bloques Try/Catch, esto quiere decir que se debe crear una función donde se procesa el error (dónde está la estructura Try/Catch, el procesamiento de errores es una cosa), desde esta se invocará la función que realizará la acción.

Antes de terminar quiero mencionar las instrucciones Switch, donde el autor hace una mención específica diciendo "Mi regla general para las instrucciones Switch es que se pueden tolerar si solo aparecen una vez, se usan para crear objetos polimórficos y se ocultan tras una relación de herencia para que el resto del sistema no las pueda ver. Evidentemente, cada caso es diferente y en ocasiones se puede incumplir una o varias partes de esta regla".

Las funciones nos ayudan a realizar acciones concretas, es nuestro deber evitar el no repetir código, por eso se deben crear con la mayor responsabilidad y dedicación y sin miedo a reescribir cuantas veces se crea necesario hasta que el resultado satisfaga las necesidades.

Nota: Para más artículos relacionados ver Clean Code.

3 comentarios:

  1. se que esto se publico hace mucho pero he estado estudiando esto y no entiendo este concepto de "argumentos de salida".

    Algunas funciones tienen "argumentos de salida", es decir, ver argumentos que en vez de ser entrada son salidas, estos argumentos deben evitarse.

    Serias tan amable de aclararlo, gracias

    ResponderEliminar
    Respuestas
    1. Hola Alejandro, sí creo que debería mejorar la explicación. Cuando hablo de argumentos de salida, me refiero a usar un argumento o parámetro de entrada como uno de salida, por ejemplo en java podría tener un método void (no devuelve nada) que reciba por parámetro un objeto carro, imaginemos que este método es llamado y dentro de dicho método el objeto pasado como parámetro es modificado, cambiando el color del carro. Luego del llamado al método sigo trabajando con mi objeto carro normalmente asumiendo que ya su color se cambió. Aparentemente no hay ningún problema pero cualquiera podría eliminar posteriormente el llamado al método y ya nuestro carro no tendría el color esperado, pero nuestro código no sabria y seguiría asumiendo que lo tiene.

      cambiarColorPorAmarrillo(carro);
      if(carro.getColor().isEquals("Amarillo")){
      // hacer algo
      }

      si alguien elimina como mencioné el llamado al método cambiarColorPorAmarrillo no se entraría en el if y el programa ya no funcionaria como se requiere. Lo mejor sería:

      carro = cambiarColorPorAmarrillo(carro);
      if(carro.getColor().isEquals("Amarillo")){
      // hacer algo
      }

      Donde el objeto carro que devuelve el método cambiarColorPorAmarrillo no es el mismo que ingresa, sino una copia del original y posterior a esto se le modifica el color.

      Espero te sirva.

      Eliminar
    2. Gracias, me sirvió tu explicación, no me había quedado clara en la lectura del libro. :).

      Eliminar

Instalación NodeJS

Ingresamos a la página oficial de NodeJS donde lo descargaremos  https://nodejs.org/en/download/ Escogemos el instalador que se ajuste a ...