function - una - varias graficas en r




¿Cuándo es una función demasiado larga? (16)

60 líneas es grande pero no demasiado larga para una función. Si cabe en una pantalla en un editor, puedes verlo todo de una vez. Realmente depende de lo que estén haciendo las funciones.

Por qué puedo romper una función:

  • Es muy largo
  • Hace que el código sea más fácil de mantener dividiéndolo y usando nombres significativos para la nueva función
  • La función no es cohesiva
  • Partes de la función son útiles en sí mismas.
  • Cuando es difícil encontrar un nombre significativo para la función (Probablemente esté haciendo demasiado)

35 líneas, 55 líneas, 100 líneas, 300 líneas? ¿Cuándo deberías comenzar a separarlo? Pregunto porque tengo una función con 60 líneas (incluyendo comentarios) y estaba pensando en separarla.

long_function(){ ... }

dentro:

small_function_1(){...}
small_function_2(){...}
small_function_3(){...}

Las funciones no se usarán fuera de la función long, haciendo que funciones más pequeñas signifiquen más llamadas de función, etc.

¿Cuándo separarías una función en otras más pequeñas? ¿Por qué?

  1. Los métodos deben hacer solo una cosa lógica (pensar en la funcionalidad)
  2. Deberías poder explicar el método en una sola oración
  3. Debe caber en la altura de su pantalla
  4. Evite gastos generales innecesarios (comentarios que señalan lo obvio ...)
  5. La prueba unitaria es más fácil para pequeñas funciones lógicas
  6. Verifique si parte de la función puede ser reutilizada por otras clases o métodos
  7. Evite el acoplamiento excesivo entre clases
  8. Evite las estructuras de control profundamente anidadas

Gracias a todos por las respuestas , edite la lista y vote por la respuesta correcta; la elegiré;)

Estoy refaccionando ahora con esas ideas en mente :)


Al extender el espíritu de un tweet del tío Bob hace un tiempo, sabes que una función se está haciendo demasiado larga cuando sientes la necesidad de poner una línea en blanco entre dos líneas de código. La idea es que si necesita una línea en blanco para separar el código, su responsabilidad y alcance se separan en ese punto.


Calcule aproximadamente el tamaño de su pantalla (así que vaya a obtener una gran pantalla panorámica pivote y gírela) ... :-)

Broma aparte, una cosa lógica por función.

Y lo positivo es que las pruebas unitarias son mucho más fáciles de hacer con pequeñas funciones lógicas que hacen 1 cosa. ¡Las funciones grandes que hacen muchas cosas son más difíciles de verificar!

/ Johan


Creo que hay una gran advertencia sobre el mantra de "hacer una sola cosa" en esta página. A veces, hacer una cosa hace malabares con muchas variables. No rompa una función larga en una serie de funciones más pequeñas si las funciones más pequeñas terminan teniendo largas listas de parámetros. Hacer eso solo convierte una sola función en un conjunto de funciones altamente acopladas sin ningún valor individual real.


En mi opinión, la respuesta es: cuando hace demasiadas cosas. Su función debe realizar solo las acciones que espera del nombre de la función en sí. Otra cosa a considerar es si desea reutilizar algunas partes de sus funciones en otros; en este caso, podría ser útil dividirlo.


Esto es, en parte, una cuestión de gusto, pero la forma en que lo determino es que trato de mantener mis funciones aproximadamente solo mientras que quepan en mi pantalla al mismo tiempo (como máximo). La razón es que es más fácil entender lo que sucede si puedes ver todo al mismo tiempo.

Cuando codigo, es una mezcla de escribir funciones largas, luego refactorizar para extraer bits que podrían ser reutilizados por otras funciones, y escribir pequeñas funciones que hagan tareas discretas a medida que avanzo.

No sé si hay una respuesta correcta o incorrecta a esto (por ejemplo, puede establecer 67 líneas como su máximo, pero puede haber ocasiones en las que tenga sentido agregar algunas más).


He escrito 500 funciones de línea antes, sin embargo, estas fueron simplemente grandes declaraciones de cambio para decodificar y responder mensajes. Cuando el código para un solo mensaje se volvió más complejo que un solo if-then-else, lo extraje.

En esencia, aunque la función era de 500 líneas, las regiones mantenidas independientemente tenían un promedio de 5 líneas.


La razón principal por la que generalmente rompo una función es porque partes de ella también son ingredientes en otra función cercana que estoy escribiendo, por lo que las partes comunes se excluyen. Además, si usa muchos campos o propiedades de otra clase, existe una buena posibilidad de que el fragmento relevante se pueda eliminar al por mayor y, si es posible, pasar a la otra clase.

Si tiene un bloque de código con un comentario en la parte superior, considere extraerlo en una función, con los nombres de función y argumento que ilustran su propósito, y reservar el comentario para la lógica del código.

¿Estás seguro de que no hay piezas allí que serían útiles en otros lugares? ¿Qué tipo de función es?


Mi idea es que si tengo que preguntarme si es demasiado largo, probablemente sea demasiado largo. Ayuda a hacer funciones más pequeñas, en esta área, porque podría ayudar más adelante en el ciclo de vida de la aplicación.


No hay reglas reales duras y rápidas para eso. En general, me gusta que mis métodos simplemente "hagan una cosa". Entonces, si está tomando datos, luego haciendo algo con esos datos, luego escribiéndolos en un disco, entonces dividiré el acaparamiento y la escritura en métodos separados, así que mi método "principal" solo contiene el "hacer algo".

Sin embargo, ese "hacer algo" podría ser un buen número de líneas, por lo que no estoy seguro de que un número de líneas sea la medida correcta para usar :)

Editar: Esta es una sola línea de código que envié por correo el trabajo la semana pasada (para demostrar un punto ... no es algo que tenga un hábito :)) - ciertamente no quisiera 50-60 de estos chicos malos en mi método :RE

return level4 != null ? GetResources().Where(r => (r.Level2 == (int)level2) && (r.Level3 == (int)level3) && (r.Level4 == (int)level4)).ToList() : level3 != null ? GetResources().Where(r => (r.Level2 == (int)level2) && (r.Level3 == (int)level3)).ToList() : level2 != null ? GetResources().Where(r => (r.Level2 == (int)level2)).ToList() : GetAllResourceList();

Normalmente utilizo un enfoque basado en pruebas para escribir código. En este enfoque, el tamaño de la función a menudo está relacionado con la granularidad de sus pruebas.

Si tu prueba está lo suficientemente enfocada, te llevará a escribir una pequeña función enfocada para que pase la prueba.

Esto también funciona en la otra dirección. Las funciones deben ser lo suficientemente pequeñas para probar de manera efectiva. Entonces, cuando trabajo con código heredado, a menudo encuentro que desgloso funciones más grandes para probar las diferentes partes de ellos.

Normalmente me pregunto "¿cuál es la responsabilidad de esta función?" Y si no puedo expresar la responsabilidad en una oración clara y concisa, y luego traducir eso en una pequeña prueba enfocada, me pregunto si la función es demasiado grande.


Regla general: si una función contiene bloques de código que hacen algo, que está algo separado del resto del código, colóquelo en una función separada. Ejemplo:

function build_address_list_for_zip($zip) {

    $query = "SELECT * FROM ADDRESS WHERE zip = $zip";
    $results = perform_query($query);
    $addresses = array();
    while ($address = fetch_query_result($results)) {
        $addresses[] = $address;
    }

    // now create a nice looking list of
    // addresses for the user
    return $html_content;
}

mucho más bonito:

function fetch_addresses_for_zip($zip) {
    $query = "SELECT * FROM ADDRESS WHERE zip = $zip";
    $results = perform_query($query);
    $addresses = array();
    while ($address = fetch_query_result($results)) {
        $addresses[] = $address;
    }
    return $addresses;
}

function build_address_list_for_zip($zip) {

    $addresses = fetch_addresses_for_zip($zip);

    // now create a nice looking list of
    // addresses for the user
    return $html_content;
}

Este enfoque tiene dos ventajas:

  1. Siempre que necesite buscar direcciones para un determinado código postal, puede usar la función disponible.

  2. Cuando necesite leer nuevamente la función build_address_list_for_zip() , sabrá qué hará el primer bloque de código (busca direcciones para un determinado código postal, al menos eso es lo que puede derivar del nombre de la función). Si hubiera dejado el código de consulta en línea, primero tendría que analizar ese código.

[Por otro lado (negaré que te dije esto, incluso bajo tortura): si lees mucho sobre la optimización de PHP, podrías tener la idea de mantener la cantidad de funciones lo más pequeña posible, porque la función de llamada es muy, muy caro en PHP. No sé nada de eso ya que nunca hice ningún punto de referencia. Si ese es el caso, es mejor que no sigas ninguna de las respuestas a tu pregunta si tu aplicación es muy "sensible al rendimiento" ;-)]


Si tiene más de tres ramas, generalmente esto significa que una función o método debe dividirse, para encapsular la lógica de bifurcación en diferentes métodos. Cada bucle for, if statement, etc. no se ve como una bifurcación en el método de llamada. El código de Cobertura para Java (y estoy seguro de que hay otras herramientas para otros idiomas) calcula el número de if, etc. en una función para cada función y lo suma para la "complejidad ciclomática promedio". Si una función / método solo tiene tres ramas, obtendrá un tres en esa métrica, lo cual es muy bueno. A veces es difícil seguir esta guía, concretamente para validar la entrada del usuario, sin embargo, poner ramas en diferentes métodos ayuda no solo al desarrollo y mantenimiento sino también a las pruebas, ya que las entradas a los métodos que realizan la bifurcación se pueden analizar fácilmente para ver qué entradas deben agregarse a los casos de prueba para cubrir las ramas que no estaban cubiertas; si todas las ramas estuvieran dentro de un único método, las entradas deberían rastrearse desde el inicio del método, lo que dificulta la capacidad de prueba.


Sospecho que encontrarás muchas respuestas sobre esto.

Probablemente lo dividiría según las tareas lógicas que se realizaban dentro de la función. Si le parece que su cuento se está convirtiendo en una novela, le sugiero que busque y extraiga distintos pasos.

Por ejemplo, si tiene una función que maneja algún tipo de entrada de cadena y devuelve un resultado de cadena, puede interrumpir la función según la lógica para dividir la cadena en partes, la lógica para agregar caracteres adicionales y la lógica para ponerlo todos juntos de nuevo como un resultado formateado.

En resumen, cualquier cosa que haga que su código esté limpio y sea fácil de leer (ya sea simplemente asegurando que su función tenga buenos comentarios o descomponerlo) es el mejor enfoque.


Una cosa (y esa cosa debería ser obvia desde el nombre de la función), pero no más que una pantalla llena de código, independientemente. Y siéntase libre de aumentar el tamaño de su fuente. Y en caso de duda, refactorice en dos o más funciones.


Una función solo debe hacer una cosa. Si está haciendo muchas cosas pequeñas en una función, haga que cada cosa pequeña sea una función y llame a esas funciones desde la función larga.

Lo que realmente no quieres hacer es copiar y pegar cada 10 líneas de tu función larga en funciones cortas (como tu ejemplo sugiere).







coding-style