¿La duración de la función afecta la productividad de un programador? Si es así, ¿cuál es un buen número máximo de líneas para evitar la pérdida de productividad?
Dado que este es un tema muy testarudo, haga una copia de seguridad del reclamo con algunos datos.
programming-practices
coding-standards
Peter Mortensen
fuente
fuente
Respuestas:
Desde que me embarqué en esta locura en 1970, he visto exactamente un módulo que realmente necesitaba tener más de una página impresa (alrededor de 60 líneas). He visto muchos módulos que eran más largos.
Para el caso, he escrito módulos que eran más largos, pero generalmente eran grandes máquinas de estados finitos escritos como grandes declaraciones de cambio.
Parte del problema parece ser que a los programadores de estos días no se les enseña a modularizar las cosas.
Los estándares de codificación que maximizan el desperdicio de espacio vertical también parecen ser parte del problema. (Todavía no he conocido a un administrador de software que haya leído la " Psicología de la programación de computadoras " de Gerald Weinberg . Weinberg señala que varios estudios han demostrado que la comprensión del programador se limita esencialmente a lo que el programador puede ver en un instante dado. el programador tiene que desplazarse o pasar una página, su comprensión cae significativamente: tienen que recordar y hacer un resumen).
Sigo convencido de que muchas de las ganancias de productividad del programador bien documentadas de FORTH se debieron al sistema de "bloques" FORTH para el código fuente: los módulos estaban limitados a un máximo absoluto de 16 líneas de 64 caracteres. Podrías factorizar infinitamente, pero bajo ninguna circunstancia podrías escribir una rutina de 17 líneas.
fuente
¿Cuál es el tamaño correcto, realmente?
Depende del idioma que use, pero en general (y para mi gusto personal):
Si es más, entonces es algo a lo que necesito volver más tarde y volver a trabajar.
Pero de manera realista , cualquier tamaño que deba ser cuando necesite entregar algo y que tenga más sentido en el momento de escupirlo de esa manera, hace que a veces sea aún más fácil que alguien lo revise antes del envío. (pero aún así vuelvo más tarde).
(Recientemente, mi equipo ejecutó un programa en nuestra base de código: encontramos clases con 197 métodos y otro con solo 3 métodos, pero uno de ellos tenía 600 líneas. Juego lindo: ¿cuál es el peor de los 2 males?)
Ahora para una respuesta más zen ... En general, se considera una buena práctica (TM) citar a uno o dos grandes hombres, así que aquí va:
Anexo sobre estilos de comentarios
Como anexo a esto, sus funciones deben tener nombres claros que expliquen su intención. Con respecto a los comentarios, generalmente no hago comentarios dentro de una función:
Un bloque de comentarios en la parte superior de cada función (que requiere explicación) es suficiente. Si su función es pequeña y los nombres de las funciones son lo suficientemente explícitos, entonces solo debe decir qué quiere lograr y por qué. Utilizo comentarios en línea solo para los campos en algunos idiomas o en los inicios de bloque para funciones que rompen esas reglas de línea 25-35 si la intención no está clara. Utilizo un comentario de bloque dentro del código cuando se produce una situación excepcional (un bloque de captura donde no necesita o no desea hacer nada debería tener un comentario que diga por qué, por ejemplo).
Para obtener más información, lea mi respuesta sobre Estilo y recomendaciones de código de comentarios
fuente
tt
para generar estos, pero a veces estás atrapado con una función de culo largo (o una función de culo larga) que de todos modos no hace nada de interés, así que no es un problema real.Map(x => x.Property1); Map(x => x.Property2); Map(x => x.Property3);
, está claro que todo es lo mismo. (Tenga en cuenta que esto es solo un ejemplo; este tipo de función aparece de vez en cuando)En mi opinión, cada función debe ser lo más pequeña posible. Cada función debe hacer solo una cosa y hacerlo bien. Eso realmente no responde a la pregunta de duración máxima, pero es más mi opinión sobre la duración de las funciones.
Para usar las palabras del tío Bob, "Extrae hasta que ya no puedas extraer nada más. Extrae hasta que caigas".
fuente
¿Cuál debería ser la altura máxima de un edificio? Depende de dónde esté la construcción o de la altura que desee que tenga.
Puede obtener diferentes respuestas de diferentes personas que provienen de diferentes ciudades.
Algunas funciones de script y controladores de interrupción del kernel son muy largas.
fuente
Un método que funciona para mí es: ¿puedo hacer que una parte de una función más larga dé un nombre que tenga sentido? Creo que la longitud de un método no es tan importante como un buen nombre. El método debe hacer lo que dice el nombre, ni más ni menos. Y deberías poder dar un buen nombre. Si no puede nombrar su método como bueno, el código probablemente no sea bueno en conjunto.
fuente
Mientras sea necesario para hacer lo que tiene que hacer, pero ya no.
fuente
Creo que hay una compensación. Si tiene muchos métodos cortos, a menudo es más difícil depurarlos que un método largo. Si tiene que saltar alrededor del editor 20 o 30 veces diferentes para rastrear una llamada de método, será difícil mantenerlo todo en su cabeza. Mientras tanto, si hay un método claro bien escrito, incluso si son 100 líneas, a menudo es más fácil mantenerlo en la cabeza.
La verdadera pregunta es por qué los elementos deberían estar en diferentes métodos, y la respuesta que se da arriba es la reutilización del código. Si no está reutilizando el código (o no lo sabe), entonces puede tener sentido dejarlo en un método gigante fácil de seguir y luego, cuando necesite reutilizarlo, divida las partes que necesitan utilizando en métodos más pequeños.
En realidad, parte del buen diseño del método es hacer métodos funcionalmente coherentes (esencialmente hacen una cosa). La longitud de los métodos no importa. Si una función hace una cosa bien definida y tiene 1,000 líneas, entonces es un buen método. Si una función hace 3 o 4 cosas y tiene solo 15 líneas, entonces es un mal método ...
fuente
Me resulta más fácil hacer un seguimiento de lo que estoy haciendo si puedo ver toda la función a la vez. Así que así es como prefiero escribir funciones:
Raramente escribo funciones más largas que eso. La mayoría de ellos son declaraciones de conmutador C / C ++ gigantes.
fuente
Para mí, una función tiene la longitud que necesita. La mayoría de las veces que lo divido es cuando reutilizaré el código.
Básicamente, me atendré al principal 'alta cohesión, bajo acoplamiento' y no hay restricción en la longitud.
fuente
La pregunta debe ser cuántas cosas debe hacer una función. Y generalmente, es raro que necesite 100 líneas para hacer "una" cosa. Una vez más, eso depende del nivel desde el que esté mirando el código: ¿una clave es el hashing de una contraseña? ¿O es hashing y guardar la contraseña una cosa?
Yo diría que empiece guardando la contraseña como una función. Cuando sienta que el hash es diferente y refactorice el código. No soy un programador experto de ninguna manera, pero en mi humilde opinión, la idea general de las funciones comienza pequeña es que cuanto más atómicas sean sus funciones, mayores serán las posibilidades de reutilización del código, sin tener que hacer el mismo cambio en más de un lugar etc.
He visto procedimientos almacenados de SQL que se ejecutan en más de 1000 líneas. ¿El número de líneas de procedimientos almacenados también es inferior a 50? No lo sé, pero hace que leer el código sea un infierno. No solo tiene que seguir desplazándose hacia arriba y hacia abajo, sino que debe asignar a algunas líneas de código un nombre como "esto valida1", "esto actualiza en la base de datos", etc., un trabajo que el programador debería haber hecho.
fuente
De la complejidad ciclomática (Wikipedia):
Recomiendo que mantenga ese número por debajo de 10 en un solo método. Si llega a 10, entonces es hora de re-factorizar.
Existen herramientas que pueden evaluar su código y darle un número de complejidad ciclomática.
Debe esforzarse por integrar estas herramientas en su canal de compilación.
No persigas literalmente el tamaño de un método, pero trata de ver su complejidad y responsabilidades. Si tiene más de una responsabilidad, probablemente sea una buena idea re-factorizar. Si su complejidad ciclomática aumenta, probablemente sea hora de re-factorizar.
Estoy bastante seguro de que hay otras herramientas que le brindan comentarios similares, pero aún no tuve la oportunidad de analizar esto.
fuente
Por lo general, trato de mantener mis métodos / funciones a lo que cabe en la pantalla de un monitor de 1680x1050. Si no encaja, utilice métodos / funciones auxiliares para repartir la tarea.
Ayuda a la legibilidad tanto en pantalla como en papel.
fuente
No pongo un límite de línea dura a nada porque algunas funciones implementan algoritmos que son intrínsecamente complejos y cualquier intento de acortarlos haría las interacciones entre las nuevas funciones más cortas tan complicadas que el resultado neto no sería una reducción en la simplicidad. Tampoco creo que la idea de que una función solo haga "una cosa" es una buena guía, ya que "una cosa" en un alto nivel de abstracción puede ser "muchas cosas" en un nivel inferior.
Para mí, una función es definitivamente demasiado larga si su longitud causa violaciones sutiles de DRY en este momento, y extraer parte de la función en una nueva función o clase podría resolver esto. Una función puede ser demasiado larga si este no es el caso, pero se podría extraer fácilmente una función o clase que haría que el código sea más modular de una manera que probablemente sea útil ante el cambio previsible en el futuro.
fuente
Suficientemente corto para ser optimizado correctamente
Los métodos deben ser tan cortos como para hacer exactamente una cosa. La razón de esto es simple: para que su código se pueda optimizar correctamente.
En un lenguaje JIT-ted como Java o C #, es importante que sus métodos sean simples para que el compilador JIT pueda producir código rápidamente. Los métodos más largos y complicados requieren naturalmente más tiempo de JIT. Además, los compiladores JIT solo ofrecen un puñado de optimizaciones y solo los métodos más simples se benefician de esto. Este hecho incluso se mencionó en el C # efectivo de Bill Wagner .
En un lenguaje de nivel inferior, como C o C ++, tener métodos cortos (tal vez una docena de líneas) también es importante porque de esa manera minimiza la necesidad de almacenar variables locales en RAM en lugar de en un registro. (También conocido como 'Registro de derrames'). Sin embargo, tenga en cuenta que en este caso no administrado, el costo relativo de cada llamada de función puede ser bastante alto.
E incluso en un lenguaje dinámico, como Ruby o Python, tener métodos cortos también ayuda en las optimizaciones del compilador. En un lenguaje dinámico, cuanto más 'dinámica' es una característica, más difícil es optimizarla. Por ejemplo, un método largo que toma una X y podría devolver un Int, Float o String probablemente funcionará mucho más lento que tres métodos separados, cada uno de los cuales solo devuelve un solo tipo. Esto se debe a que, si el compilador sabe exactamente qué tipo devolverá la función, también puede optimizar el sitio de llamada de la función. (Por ejemplo, sin verificar las conversiones de tipos).
fuente
Depende mucho de lo que haya en el código.
He visto una rutina de mil líneas con la que no tuve ningún problema. Fue una declaración de cambio enorme, ninguna opción superó una docena de líneas y la única estructura de control en cualquier opción era un solo bucle. En estos días se habría escrito con objetos, pero esa no era una opción en ese momento.
También estoy mirando 120 líneas en un interruptor frente a mí. Ningún caso supera las 3 líneas: un guardia, una asignación y el descanso. Está analizando un archivo de texto, los objetos no son una posibilidad. Cualquier alternativa sería más difícil de leer.
fuente
A la mayoría de los compiladores no les importa la longitud de una función. Una función debe ser funcional, pero ser fácil de entender, cambiar y reutilizar para los seres humanos. Elija la longitud que más le convenga.
fuente
Mi regla general es que una función debe caber en la pantalla. Solo he encontrado tres casos que tienden a violar esto:
1) Funciones de despacho. En los viejos tiempos, estos eran comunes, pero la mayoría de ellos se reemplazan con la herencia de objetos en estos días. Sin embargo, los objetos solo funcionan dentro de su programa y, por lo tanto, aún verá funciones de despacho ocasionales al tratar con datos que llegan de otro lugar.
2) Funciones que hacen un montón de pasos para lograr un objetivo y donde los pasos carecen de una buena subdivisión. Terminas con una función que simplemente llama a una larga lista de otras funciones en orden.
3) Como # 2 pero donde los pasos individuales son tan pequeños que simplemente están en línea en lugar de llamarse por separado.
fuente
Quizás la longitud de la función no sea tan buena métrica. Intentamos utilizar la complejidad ciclomática , también en los métodos, y una de las futuras reglas de control de origen que establece que la complejidad ciclomática en las clases y los métodos debe ser inferior a X.
Para los métodos, X se establece en 30, y eso es bastante ajustado.
fuente