Directriz de codificación: ¿Los métodos no deben contener más de 7 declaraciones?

78

Estaba mirando las Pautas de codificación de AvSol para C # y estoy de acuerdo con casi todo, pero tengo mucha curiosidad por ver qué piensan los demás de una regla específica.

AV1500

Los métodos no deben exceder las 7 declaraciones Un método que requiere más de 7 declaraciones está haciendo demasiado o tiene demasiadas responsabilidades. También requiere que la mente humana analice las declaraciones exactas para comprender lo que está haciendo el código. Divídalo en múltiples métodos pequeños y enfocados con nombres autoexplicativos.

¿La mayoría de ustedes siguen esta regla? ¿Incluso si hay poco que ahorrar al crear un nuevo método (su código aún está SECO ), aparte de una gran legibilidad? ¿Y su número sigue siendo tan bajo como 7? Yo tendería más hacia 10.

No digo que viole esta regla por todas partes; por el contrario, mis métodos son 95% pequeños y centrados, pero decir que nunca deberías violar esta regla realmente me dejó alucinado.

Realmente solo quiero saber qué piensan todos de NUNCA violar esta regla (es un '1' en el estándar de codificación, lo que significa que NUNCA haga esto). Pero creo que tendría problemas para encontrar una base de código que no lo haga.

brian
fuente
48
¿Cuentan también las casedeclaraciones en una chamusquina switch? De cualquier manera, no es más que un requisito idiota e inútil. Quienes lo escribieron no saben nada de programación.
SK-logic
86
La única regla que debería ser un '1' en el estándar de codificación debería ser la regla "tomará todas las pautas de codificación con un grano de sal".
Mike Nakis
66
@ SK-logic 1027 tampoco está mal: debe ser divertido escribir código que tenga que manejar los datos faltantes, si tiene que tratar la cadena vacía como una cadena nula.
quant_dev
25
Al leer esta guía, esperaría ver una base de código llena de: void DoSomething () {DoSomethingFirstSevenLines (); DoSomethingSecondSevenLines (); DoSomethingThirdSevenLines (); etc; }
tirones
12
Intente reflejar la mayor parte de .NET Framework y vea cuántos métodos tienen menos de 7 declaraciones ...
David Boike

Respuestas:

195

Este es un "olor estándar" para mí. Cada vez que veo estándares de codificación con límites específicos, me preocupo. Casi siempre te encuentras con un caso en el que un método debe ser más grande de lo que permite el estándar (ya sea longitud / recuento de línea, número de variables, número de puntos de salida, etc.). Las normas deberían parecerse más a las directrices y permitir un margen de maniobra suficiente para ejercer un buen juicio. No me malinterpreten, es bueno tener estándares, pero no deberían convertirse en "microgestión por poder".

TMN
fuente
25
+1 para "microgestión por proxy". Sospecho que alguien leyó acerca de la regla "7 más o menos 2" ( en.wikipedia.org/wiki/… ) y confundió la retención de hechos a corto plazo con el almacenamiento a largo plazo como, ya sabes, un editor de código.
esponjoso
25
Cualquier estándar bien pensado prohíbe los números mágicos en el código, ¿verdad? Uno pensaría que el estándar de codificación también se mantendría en ese estándar. El número 7 definitivamente tiene una cualidad ciertamente "mágica".
Adam Crossland
2
Su respuesta tendría más sentido si el título del documento no fuera "Codificación Guidlinespara C # 3.0 y 4.0.
Andy
+1 En mi opinión, la única razón por la que debe seguir los estándares de codificación es nunca seguir dogmáticamente un número arbitrario, sino asegurarse de no causar problemas de fusión innecesarios en el control de versiones (es decir, problemas asociados cuando trabaja en un equipo). Por lo general, los archivos más cortos y más componentes significan menos posibilidades de que tenga problemas al combinar cambios de código.
Spoike
3
Descargué este documento y comencé a buscarlo. En 1.6, dice: "El documento no establece que los proyectos deben cumplir con estas pautas, ni dice qué pautas son más importantes que otras. Sin embargo, alentamos a los proyectos a decidir qué pautas son importantes, qué desviaciones tendrá un proyecto use, quién es el consultor en caso de que surjan dudas, y qué tipo de diseño debe usarse para el código fuente ". Aunque un 1 significa "Directrices que nunca debe omitir y que deben aplicarse a todas las soluciones", puede optar por modificarlo.
cristiano
83

Por lo general, es una buena idea dividir las cosas en pequeños métodos. Pero lo importante es dividir las cosas donde tenga sentido.

Si no tiene sentido dividirse, entonces no se divida. Este suele ser el caso de algunos procedimientos o código GUI.

Steve McConnell declaró en Code Complete que no siempre eres más productivo cuando usas métodos cortos. Si se divide cuando no tiene sentido, agrega complejidad al código sin ningún beneficio.

Como siempre con las pautas, es bueno recordar por qué existen las restricciones, para que pueda aprender cuándo no se aplica. En la mayoría del código, los métodos serán cortos, o probablemente tenga un problema con DRY o separación de preocupaciones . Pero si no es el caso, entonces está bien.

deadalnix
fuente
1
Gran respuesta. Las últimas dos líneas conducen especialmente a casa el punto.
Xonatron
66
Creo que la regla general importante es verificar si los submétodos son ortogonales. Si son independientes, se pueden llamar en cualquier orden y respetar la clase invariante, entonces es mejor mantenerlos separados. Si los métodos están estrechamente acoplados, rompen las clases invariantes y / o necesitan ser llamados en un cierto orden, entonces quizás sea mejor mantenerlos juntos.
hugomg
44
El código completo está lleno de cosas buenas. Todos los programadores deben comer un trozo en el almuerzo todos los días.
deadalnix
29

Debe considerarse como una regla de oro.

Cosas como "No más de 80 (100,120) columnas de texto", "un punto de salida por método", "no más de 2 niveles de anidamiento", son lo que yo llamaría umbrales para indicadores de olor de código. Si los viola en alguna ocasión, eso no significa necesariamente que el código sea malo. Si se encuentra violando constantemente, entonces algo huele en el código y es posible que desee hacer una pausa y repensar su enfoque.

Para mí, los criterios más importantes son: "¿Es comprensible este código?", "¿Es repetitivo?", "¿Está dividido en lugares lógicos?", "¿Está acoplado de forma flexible?" Hay algunos más, pero creo que la idea básica se puede resumir recordando el consejo de Donald Knuth: "Los programas deben ser leídos por humanos y solo de manera incidental para que las computadoras los ejecuten".

seggy
fuente
77
El límite de columnas "80/100/120" es para que podamos leer el código. La mayoría de los terminales se abren en 80 columnas, y es menos esfuerzo hacer que el autor se ajuste a 80 columnas que hacer que cada lector cambie el tamaño de su terminal cada vez que quiera leer el código. A diferencia de los otros límites, el límite de la columna N no afecta la semántica del código, es una regla puramente estilística; en la misma categoría que "usar pestañas de 4 espacios" o "poner llaves de apertura para funciones en su propia línea".
Dietrich Epp
44
Por supuesto, es un aspecto estético más que un aspecto semántico. Sin embargo, ahí es donde se aplica mi última oración. No es raro encontrar declaraciones Java que excedan la regla de 80 columnas sin un lugar "agradable" para dividir la línea. Esto afecta la legibilidad y la comprensión del código. También podría indicar violaciones de la Ley de Deméter
seggy
77
En el siglo XXI, mi IDE tiene esta característica llamada "ajuste dinámico de palabras".
György Andrasek
99
@ GyörgyAndrasek: Pero todos no siempre usan su IDE: miramos el código en GitHub, en terminales con less, en vimy emacs; y el envoltorio automático parece al azar en el mejor de los casos. Los estándares de codificación no son para su beneficio, son para el beneficio de las personas que trabajan en equipo.
Dietrich Epp
2
@DietrichEpp Personalmente, me cuesta leer el código, que siempre está envuelto en la columna 80. Recientemente tuve que trabajar en un proyecto Java donde se utilizó el formateador Eclipse estándar. Y dentro de un método fue muy difícil hacer un seguimiento de las líneas que pasaron por dos o incluso tres líneas (aunque también culpo a los otros ajustes del formateador). La conclusión es que creo que el 80 está un poco desactualizado. Personalmente uso un límite de 120, tengo mis editores configurados para hacer cumplir eso, tengo una consola que tiene 120 columnas de ancho y Github realmente muestra 125 columnas. Y creo que es mucho más legible así.
meter
18

Nunca me he tomado el tiempo para contar realmente el número de declaraciones en mis métodos, pero me esfuerzo por escribir métodos que realicen limpiamente un único propósito claro. Siempre que su código sea limpio, legible y siga los principios DRY y de responsabilidad única , probablemente haya hecho su trabajo. Creo que dividir arbitrariamente un método para hacer cumplir el límite de siete instrucciones podría hacer que su código sea menos legible / mantenible.

Joshua Smith
fuente
1
+1 para legibilidad. Ni siquiera debería importar si un método tiene 20, 30 o incluso 50 líneas de largo. Si DRY y SRP son sus objetivos, no importará si los métodos parecen ser un poco largos ... aunque a menudo encontrará que cuanto más legible intente hacer su código, más cortos serán sus métodos naturalmente se convertirá.
S.Robins
11

Es aproximado

Este tipo de reglas no deben tomarse demasiado literalmente. Podrían haber dicho "los métodos deberían ser cortos ". Sin embargo, algunas personas lo habrían interpretado como "menos de 1 página" y otras como "2 líneas como máximo".

Supongo que dijeron "7 declaraciones" para darle una idea aproximada (aunque creo que deberían haber dicho "aproximadamente 7"). Si necesita 9 de vez en cuando, no se preocupe. Pero si está llegando a 20, sabrá que no está en el estadio correcto para esta regla.

Nathan Long
fuente
Eso lo convierte en una aproximación bastante explícita entonces. Está marcado en "Directrices que nunca debe omitir y debe ser aplicable a todas las situaciones".
Brian
1
@brian: tal vez los escritores de las guías omitieron accidentalmente la palabra "más o menos", o tal vez eran tipos de dictadores locos. Mi punto es que el OP debería tomar esto como un número de estadio. Cualquier regla que el compilador o el intérprete no aplique es solo una sugerencia.
Nathan Long
"Cualquier regla que el compilador o el intérprete no aplique es solo una sugerencia" No necesariamente es cierto. No he mirado sus reglas personalizadas de resharper o fxcop y si realmente hacen cumplir esta regla en particular, pero hay compañías que lo obligan a validar contra todas las pautas de estilo. He conocido personas cuya compañía los obliga a escribir código que puede pasar las estrictas pautas de codificación de Microsoft.
Brian
Estoy de acuerdo en que es aproximado y que debe tomarse por un grano de sal, tener un párrafo del código estándar para que aparezca un número arbitrario inevitablemente causará confusión. La mayoría de las veces los estándares se sacarán de contexto y las "personas" seguirán esa aproximación arbitraria como un dogma.
Spoike
10

7 es un número completamente arbitrario sin ningún significado.

La complejidad ciclomática es un problema mayor que el número de declaraciones. He visto código que tenía cientos de declaraciones en un solo método (lo que me pareció terrible), pero tenía una complejidad ciclomática de 1 y realmente solo hizo 1 cosa. Solo había muchos pasos. Discutimos dividirlo en métodos más pequeños, pero esos métodos solo serían llamados por este método.

Si bien ese es un caso bastante extremo, el punto es que debe mantener el código SECO y una baja complejidad ciclomática. Eso es más importante que el número de líneas en un método.

Tome una declaración de cambio / caso, por ejemplo. Si tiene más de 7 valores posibles, ¿necesita dividir la evaluación en varios métodos? Por supuesto que no, eso sería una tontería.

La división artificial del código en más métodos solo para mantener el número de declaraciones por debajo de 7 solo empeora su código.

La directriz debe ser Cada método debe hacer 1 cosa y mantener su código SECO.

Jim McKeeth
fuente
1
+1: los límites arbitrarios solo son arbitrariamente útiles. Un método debe contener una única operación coherente en un único nivel de abstracción. Romper una unidad atómica de este tipo hace que el código sea más complejo, lo que dificulta su comprensión.
Allon Guralnek
DRY está sobrevalorado. Muy a menudo significa unir dos aspectos de algo que no debería estar tan estrechamente acoplado.
Brad Thomas
4

Bueno, depende un poco. Escribo mucho código que accede a las bases de datos. El código de la placa de la caldera para el manejo de excepciones tiene más de siete declaraciones en muchos casos. Yo diría que la mejor guía es asegurarse de que su función tenga un propósito

Jaydee
fuente
8
¿No puede abstraer el código repetitivo en su propio método?
erjiang
Después de publicar, noté que esto es C #, no Java, pero estoy pensando en este tipo de cosas. stackoverflow.com/questions/321418/…
Jaydee
@erjang: puedes. Es muy feo en Java, ya que debe ajustar cada consulta en una clase anónima, pero aún así vale la pena hacerlo. No es tan feo en C #, y definitivamente vale la pena hacerlo.
Kevin Cline
Personalmente, creo que algunas líneas adicionales de código de línea directa son más legibles. Pero tal vez solo soy yo.
Jaydee
@Jaydee La pregunta vinculada muestra una práctica común pero extraña: envolver una excepción e iniciar sesión. En el siguiente nivel, puede hacer lo mismo ... de esta manera, una sola excepción aparece varias veces en el registro. Sería mejor declarar el método de lanzamiento y guardar 3 líneas. Escribir un método de ayuda cierre tanto psy rsy guardar otro. O escriba un método List<Row> readDb(String sql, Object... args)que haga todo el trabajo (solo funciona para los conjuntos de resultados que se ajustan en la memoria, pero obtener demasiados datos generalmente implica que el trabajo debe realizarse en la base de datos de todos modos).
maaartinus
4

Todo es una compensación. El problema con el enfoque propuesto (refactorización en varios métodos y clases para que cada método sea breve) es que, aunque por diferentes razones, conduce a un código ilegible cuando se lleva al extremo.

Imagine un método foo()que hace 7 cosas. Se podría argumentar que 7 cosas son demasiado. Quizás en muchos casos tengas razón. Por otro lado, estas 7 cosas podrían estar estrechamente relacionadas; la lógica puede fluir suavemente y leerse como prosa; Es posible que no tenga problemas para entenderlo cuando realmente lo necesite. Lo que podría terminar mucho peor es tener esas 7 cosas distribuidas en un gran árbol fuente, de modo que si observas foo()no tienes idea de lo que hace sin mirar en 7 lugares diferentes.

Muchas personas tienen reglas como esta en su cabeza, y el resultado es lo que yo pienso como OO spaghetti. Todo está ordenado, en caja en su propio pequeño método o clase, con pequeñas micro transacciones atómicas que ocurren en cada lugar. Pero es imposible llegar a una base de código de este tipo y saber lo que está haciendo. Te pierdes.

asveikau
fuente
4

No es una mala directriz. Nunca me he arrepentido de dividir los métodos y las clases (nunca he descubierto que tenía demasiados) siempre y cuando estén agrupados e interrelacionados lo suficientemente bien.

El truco es NO dividirlo verticalmente (solo pellizca un método en un punto y comienza uno nuevo). El truco, al igual que con las pruebas unitarias, es tener en cuenta esa regla desde el principio para que realmente diseñe mejor, pasando 3 o 4 declaraciones a medio método a otro método porque tener una llamada al método describe lo que está haciendo mejor que esas 3 o 4 declaraciones en el medio de su código.

Este tipo de división, incluso si es arbitrario y solo se usa una vez, puede conducir a mejores refactorizaciones posteriores debido a una nueva claridad de código, esto también es cierto para las clases más pequeñas.

Piense en ello como si fuera una unidad de prueba. Si intenta agregar pruebas unitarias después del hecho, es difícil y a veces parece imposible, pero si lo diseña desde el principio, en realidad mejora todo su código.

¿Resumen? Si comparo el olor del diseño de "Usar menos de 7 declaraciones" con el olor del código de "Usé más de 7 declaraciones", prefiero eliminar el olor del código.

Bill K
fuente
4

¡Guauu! Nunca esperé encontrar una discusión tan intensa sobre una guía simple que diga más o menos que sus métodos deberían ser muy pequeños. Debido a que siempre son desarrolladores que quieren que sus pautas sean explícitas, elijo 7 porque eso sonaba como un buen umbral.

Algunos de ustedes ya han citado la exención de responsabilidad al comienzo del documento. Pero para ser claros, este documento representa una colección de pautas que intentan ayudarlo a escribir mejor código y diseñar mejores sistemas. Nunca he dicho que algo debería ser una regla, a pesar de que una directriz está marcada como un nivel 1. Esos niveles son simplemente la opinión colectiva de las muchas personas que han estado usando este documento por un tiempo.

Tampoco he afirmado nunca ser un experto. Pero llevo 15 años en esta profesión, con aproximadamente 4 años de experiencia en C ++ y 11 años de experiencia en C #. Originalmente se basó en Industrial Strength C ++, pero lo he estado refinando desde entonces con el aporte de la comunidad.

De todos modos, el punto que estaba tratando de plantear es que debes seguir pensando por ti mismo. Si crees que la directriz de 7 declaraciones no es útil, solo hazla más larga. Diablos, incluso violo esa pauta de vez en cuando. Simplemente lo violo seriamente y acepto las consecuencias.

Dennis Doomen
fuente
3
Me alegro de que intervengas, y creo que tienes un argumento razonable. Dicho esto, no estoy de acuerdo con su justificación "siempre son desarrolladores que quieren que sus pautas sean explícitas": no siempre puede atender a los idiotas, y no debe intentarlo. Hacer explícitas las pautas es bueno siempre que esto no las vuelva incorrectas: ahora ya no es una pauta, es una regla arbitraria. Introducir números arbitrarios, como has visto, es una forma segura de ser derribado y justificado.
Konrad Rudolph
3

Primero: es una guía, no una regla. Se llama una guía, así que trátela como tal. Esto implica que también se requiere su propio juicio (como siempre)

Aparte de eso, puedo pensar en muchos ejemplos de buen código que no se adhiere a esta restricción. Aunque es solo una guía, es pobre.

Dominic Cronin
fuente
2

Estoy de acuerdo con la declaración sobre mí. Esto es solo una guía y en un mundo perfecto todo sería objetos, reutilizados en cada programa, y ​​el mundo sería un lugar hermoso. No siempre es cierto y, a veces, eso llevaría a una gran cantidad de gastos generales o desperdicio de recursos. Tienes que tener eso en cuenta también.

Falcon165o
fuente
66
"Estoy de acuerdo con la afirmación sobre mí" Evite este tipo de oraciones en los sitios de intercambio de pila. Recuerde que el orden en que se publican las respuestas no es necesariamente el orden en que se muestran.
luiscubal
Lo sé, no pensé hasta que fue demasiado tarde. Pero todavía haré +1 por señalar mi pedo cerebral.
Falcon165o
2

Bastante tonto cuando agrega manejo de excepción a la mezcla.

¡Después de "intentar, atrapar, finalmente" te quedan cuatro afirmaciones por método!

También considere un método "validateForm" para un formulario de 20 campos, incluso si maneja todas las validaciones individuales en métodos separados, todavía tiene 20 métodos de validación de campo para invocar. De acuerdo con estas pautas, terminaría con una división inútil como "validateTopOfScreen", "validateMiddleOfScreen" y "validateBottomOfScreen".

James Anderson
fuente
Creo que es bastante seguro decir que try/ catch/ finallyno son declaraciones en C #. Ver Ecma-334 § 12.3.3.15 y las secciones circundantes. (abreviado) " una declaración try-catch-finally de la forma : try try-block catch (...) catch-block-n finally finally-block "
un CVn
Bueno, como dije antes, es una decisión que debes tomar una y otra vez. Sin embargo, su ejemplo particular podría ser un ejemplo de no hacer el diseño orientado a objetos correctamente. Es posible que desee dividir su pantalla en múltiples controles que hacen la validación ellos mismos.
Dennis Doomen
@Dennis: es cierto, ¡he estado haciendo formularios HTML durante demasiado tiempo!
James Anderson
@James Y para eso está destinada esta guía en particular. Tratando de hacerte pensar en soluciones alternativas, potencialmente mejores.
Dennis Doomen
2

La pregunta es combinar "reglas" con "pautas". Las reglas están destinadas a ser obedecidas: las pautas son consejos que deben hacer que considere lo que está haciendo y si realmente podría hacerse de una mejor manera.

Yo diría que, en promedio, la mayoría de la programación probablemente mejore al seguir las pautas, pero siempre habrá casos en los que seguir las pautas dogmáticamente causará más problemas de los que pretendían resolver. Es por eso que no se presentan como reglas, sino como pautas.

Un respondedor anterior demostró que los escritores de las directrices nunca pretendieron que se aplicaran dogmáticamente e incluyeron declaraciones a tal efecto en su documento.

authentictech
fuente
0

Estoy de acuerdo con los comentarios anteriores. 7 para mí es arbitrario y puede ser útil en algunos lenguajes donde ruby, pero para lenguajes como C #, Java, C ++ dudo de esta convención de "7 líneas". Permítanme darles un ejemplo. Mi aplicación actual tiene 22 campos de texto y hago la validación del lado del servidor. El método se llama validateInput () y mi preferencia es validar todos los campos en un mismo método a menos que haya validado algo complejo como checkEmailFormat (). Entonces, básicamente, mi código del método validateInput es 108 líneas con llamadas ocasionales a validación compleja.

Ahora imagine si llamé a 25 métodos para validar cada campo. Si entra un nuevo desarrollador, tendrá que entrar y salir del método principal para saltar a través de 25 métodos que a su vez podrían estar llamando a algunos otros. Está obligado a perderse en grandes proyectos.

Lo que realmente hago para aclarar mi código es proporcionar comentarios limpios que básicamente dicen lo que están haciendo estas 4 líneas, por ejemplo:

validateInput (usuario UserObj) {

// Validar nombre ....... ......

// validar apellido ...... ......

// validar correo electrónico ..... // demasiado complejo para verificar el formato de correo electrónico regular express checkEmailFormat (); .... .....

y así.. }

Dinesh Arora
fuente
1
Vea también mi respuesta a la pregunta de James Andersons. En su caso particular, me pregunto si ese método de validación no está violando varios principios y pautas al mismo tiempo.
Dennis Doomen
0

Mala regla Con el código para el manejo de excepciones, la configuración de los campos de la base de datos, la validación, ¿cómo pueden la mayoría de los métodos estar bajo siete declaraciones? ¿Nunca deberíamos hacer funciones lambda en línea?

Las líneas de código son un recuento arbitrario de complejidad. Con los métodos de extensión puedo crear código como

                Parallel.ForEach(regions, region => {   Console.Write(region.Resorts.Where(x => x.name == "Four Seasons").OrderBy(x => x.RegionId).ThenBy(x => x.ResortId).ThenBy(x => x.name).ToList());   });
Justin
fuente
Nuevamente, un gran ejemplo de hacer demasiado en un solo método. En casi todos los contraargumentos, las personas están violando el Principio de responsabilidad única (en el contexto de un método).
Dennis Doomen
-1

Todos los programadores junior deberían verse obligados a adherirse a este principio. Eso los obligaría a pensar en la estructura de lo que están ocupados, en lugar de simplemente agregar más y más código de líneas.

Actualmente estoy viendo un método de 550 líneas de código con muchas declaraciones if else y continúa y devuelve entretejido. Es basura. Si el programador solo se hubiera visto obligado a pensar en lo que estaba haciendo ...

Dawidg
fuente