Odio hacer referencia al contenido de pago, pero este video muestra exactamente de lo que estoy hablando. Precisamente 12 minutos en Robert Martin mira esto:
Y dice "Una de mis cosas favoritas para hacer es deshacerme de los frenos inútiles" mientras lo convierte en esto:
Hace mucho tiempo, en una educación muy lejana, me enseñaron a no hacer esto porque facilita la introducción de un error al agregar otra línea con sangría pensando que está controlada por el if
cuando no lo está.
Para ser justos con el tío Bob, está refactorizando un método largo de Java a pequeñas funciones que, estoy de acuerdo, son mucho más legibles. Cuando termina de cambiarlo, (22.18) se ve así:
Me pregunto si se supone que eso valida la eliminación de las llaves. Ya estoy familiarizado con las mejores prácticas . ¿Se puede desafiar al tío Bob en este punto? ¿El tío Bob ha defendido la idea?
fuente
if
bloque es solo una línea, no importa. Si necesita agregar más líneas, debería ser otra función que reduzca elif
bloque a una línea (la llamada a la función). Si te adhieres a eso, entonces los frenos simplemente no importan, en absoluto .return (page==null) ? "" : includePage(mode,page);
si le gusta tanto hablar ... He pensado que el estilo sin corsé es genial hasta que comencé a desarrollar aplicaciones profesionalmente. Ruido difuso, posibles errores tipográficos, etc. Los aparatos ortopédicos, al estar allí todo el tiempo, le ahorran el tiempo y la sobrecarga que necesitaría para presentarlos más adelante.Respuestas:
La legibilidad no es poca cosa.
Soy de una mente mixta cuando se trata de llaves que encierran un solo método. Personalmente los elimino para cosas como declaraciones de devolución de una sola línea, pero dejar esas llaves en realidad nos mordió muy duro en el último lugar donde trabajé. Alguien agregó una línea de código a una
if
declaración sin agregar también las llaves necesarias, y debido a que era C, bloqueó el sistema sin previo aviso.Nunca desafío a nadie que sea religioso acerca de usar siempre aparatos ortopédicos después de ese pequeño fiasco.
Por lo tanto, veo el beneficio de la legibilidad, pero soy muy consciente de los problemas que pueden surgir cuando se dejan esos frenos.
No me molestaría en tratar de encontrar un estudio o la opinión publicada de alguien. Todos tienen una (una opinión, es decir), y debido a que es un tema estilístico, una opinión es tan buena como cualquier otra. Piensa en el problema tú mismo, evalúa los pros y los contras, y toma tu propia decisión. Si la tienda para la que trabaja tiene un estándar de codificación que cubre este problema, solo siga eso.
fuente
-Wmisleading-indentation
.Puede encontrar varias promociones publicadas o rechazos de estilos sin abrazaderas aquí o aquí o donde se pintan los cobertizos para bicicletas.
Al alejarse de los cobertizos para bicicletas, ¿ recuerda el gran error de OS X / iOS SSL de 2014?
Sí, "causado" por bloques sin llaves https://www.imperialviolet.org/2014/02/22/applebug.html
Las preferencias pueden depender del estilo del corsé. Si tuviera que escribir
Podría estar inclinado a ahorrar espacio también. Pero
solo usa una línea "extra".
Sé que no preguntaste, pero si estoy trabajando solo, soy un hereje. Si me quito las llaves, prefiero
No tiene el mismo problema visual que el error de estilo SSL de iOS, pero guarda incluso más líneas "innecesarias" que el tío Bob;) Se lee bien si está acostumbrado y tiene un uso convencional en Ruby (
includePage(mode, suiteSetup) unless suiteSetup.nil?
). Oh, bueno, solo sé que hay muchas opiniones.fuente
} else[if(...)] {
, eso no agrega líneas adicionales adicionales, por lo que agrega solo una línea adicional en todo el conjunto.El tío Bob tiene muchas capas de defensa contra tal error que no eran tan comunes cuando "siempre usa llaves" era la sabiduría predominante:
Creo que si alguien publicara un desafío al tío Bob, tendría una muy buena refutación con los puntos anteriores. Este es uno de los errores más fáciles de detectar temprano.
fuente
while(true);{break;}
. Si realmente hay un contexto válido para esto, me llevará un tiempo superarlo.includePage()
no es una macro mal escrita con más de una declaración?En su mayor parte, esta es una preferencia personal, sin embargo, hay algunas cosas a considerar.
Posibles errores
Si bien se puede argumentar que los errores causados por el olvido al complemento de los frenos son raros, por lo que he visto que ellos no ocurren de vez en cuando (no olvidar el famoso Goto IOS falla error). Así que creo que esto debería ser un factor al considerar el estilo de su código (algunas herramientas advierten sobre sangría engañosa , por lo que también depende de su cadena de herramientas) .
Válido Código (que se lee como que podría ser un error)
Incluso suponiendo que su proyecto no sufre de este tipo de errores, al leer el código es posible que vea algunos bloques de código que parecen que podrían ser errores - pero no es así, tomando algunas de sus ciclos mentales.
Comenzamos con:
Un desarrollador agrega un comentario útil.
Más tarde, un desarrollador se expande en él.
O agrega un bloque anidado:
O usa una macro:
"... Dado que las macros pueden definir varias líneas de código, ¿la macro usa
do {...} while (0)
varias líneas? Debería porque está en nuestra guía de estilo, ¡pero es mejor que lo verifique por si acaso!"Los ejemplos anteriores son todos códigos válidos, sin embargo, cuanto más contenido en el bloque de código, más necesita leer para asegurarse de que no haya errores.
Tal vez su estilo de código define que los bloques de varias líneas requieren una llave (no importa qué, incluso si no son código) , pero he visto este tipo de comentarios agregados en el código de producción. Cuando lo lees, hay una pequeña duda de que quien editó esas líneas por última vez se olvidó de agregar un paréntesis, a veces siento que la necesidad de verificar dos veces está funcionando según lo previsto (especialmente cuando se investiga un error en esta área del código) .
Ruido difuso
Una razón práctica para usar llaves para líneas simples es reducir el ruido diferencial .
Es decir, cambiando:
A:
... hace que la línea condicional se muestre en un diff como modificada, esto agrega una sobrecarga pequeña pero innecesaria.
Dicho esto, no todas las herramientas son compatibles con la diferenciación basada en palabras, diff (svn, git, hg ... etc.) se mostrará como si toda la línea cambiara, incluso con herramientas sofisticadas, a veces es posible que necesite mirar rápidamente sobre una línea simple basado en diff para ver qué cambió.
git blame
) mostrarán la línea como modificada, haciendo que el seguimiento del origen de una línea sea más paso para encontrar el cambio real .Ambos son pequeños y dependen de la cantidad de tiempo que dedique a revisar o rastrear el código que confirma las líneas de código cambiadas.
Un inconveniente más tangible de tener cambios de líneas adicionales en una diferencia, su mayor probabilidad de que los cambios en el código causen conflictos que se fusionen y deben resolverse manualmente .
Hay una excepción a esto, para las bases de código que tienen
{
en su propia línea, no es un problema.El argumento de ruido diferencial no se cumple si escribe en este estilo:
Sin embargo, esta no es una convención tan común, por lo que se agrega principalmente a la respuesta para completar (no sugerir que los proyectos deberían usar este estilo) .
fuente
{
estilo de línea propia. Realmente odio ese estilo, y no me gusta trabajar en proyectos donde se requiere ese estilo. Tal vez con eso en mente, me resultará un poco menos frustrante tener que codificar de esa manera. La densidad del código es importante. Si puede ver todas las funciones en su monitor a la vez, puede asimilar todo más fácilmente. Me gusta dejar líneas en blanco entre bloques de código separados dentro de una función para facilitar la lectura (agrupar declaraciones relacionadas), y ser forzado a desperdiciar espacio en otros lugares debilita los descansos previstos.{
estilo de línea propia, solo lo incluyó para completar las respuestas. En cuanto a confiar en el uso de macrosdo{}while(0)
, creo que el problema con esto es que puedes confiar en él casi todo el tiempo. El problema es que los accidentes ocurren, los errores pueden pasar por la revisión del código ... y se pueden introducir errores que no hubieran sido de otra manera.Hace años, me llevaron a depurar un código C. El error fue una locura difícil de encontrar, pero finalmente se redujo a una declaración como:
Y resultó que la persona que lo había escrito se había definido
foo
como una macro. Una macro con dos líneas de código. Y, por supuesto, solo la primera de esas dos líneas estaba sujeta aif
. (Entonces la segunda línea se ejecutó incondicionalmente).Esto puede ser absolutamente exclusivo de C y su preprocesador, que realiza sustituciones antes de la compilación, pero nunca lo he olvidado. Ese tipo de cosas te deja huella, y ¿por qué no jugar con seguridad, especialmente si usas una variedad de idiomas y cadenas de herramientas y no puedes estar seguro de que tales travesuras no sean posibles en otro lugar?
Ahora sangro y uso frenillos de manera diferente a los demás, aparentemente. Para una sola línea
if
, haría:por lo que no se necesitan líneas adicionales para incluir los corchetes.
fuente
do { ... } while(0)
bucle. Esto no solo asegurará que siempre se tratará correctamente mediante lasif()
declaraciones adjuntas , sino también que el punto y coma al final de la declaración se traga correctamente. Quien no conozca estas reglas simples, simplemente no debe escribir macros de preprocesador. Defender en el sitio de llamadas es el lugar equivocado para defender.Al "tío Bob" se le permite tener su opinión, a usted se le permite tener su opinión. No hay necesidad de desafiarlo.
Si desea apelar a la autoridad, tome Chris Lattner. En Swift, si las declaraciones perdieron sus paréntesis, pero siempre vienen con llaves. Sin discusión, es parte del lenguaje. Entonces, si "Tío Bob" comienza a quitar llaves, el código deja de compilarse.
Revisar el código de otra persona y "deshacerse de los frenos inútiles" es un mal hábito. Solo causa trabajo adicional cuando el código necesita ser revisado, y cuando los conflictos se crean innecesariamente. ¿Quizás "Tío Bob" es un programador tan increíblemente bueno que no necesita revisiones de código? Perdí una semana de mi vida porque un programador superior cambió "if (p! = NULL)" a "if (! P)" sin una revisión de código, oculto en el peor lugar posible.
Este es principalmente un debate de estilo inofensivo. Las llaves tienen la ventaja de que puede insertar otra línea de código sin agregar llaves. Como una declaración de registro, o un comentario (si es seguido por un comentario seguido de una declaración es simplemente horrible). declaración en la misma línea como si tuviera la desventaja práctica de que tiene problemas con muchos depuradores. Pero haz lo que prefieras.
fuente
Mis razones para no quitar llaves son:
reducir la fatiga de decisión. Si siempre usa aparatos ortopédicos, nunca tendrá que decidir si los necesitará o no.
reduzca el arrastre de desarrollo: incluso si se esfuerza por extraer eventualmente todas las líneas múltiples de lógica a métodos, tener que convertir un sin corsé si en un corsé si agregar lógica es un poco molesto de arrastre de desarrollo. Por lo tanto, existe el esfuerzo de eliminar las llaves, y el esfuerzo de agregarlas nuevamente cuando necesita más código. Diminuto, pero molesto.
fuente
Un joven compañero de trabajo ha dicho que los aparatos ortopédicos que consideramos redundantes y superfluos son de hecho útiles para él. No recuerdo exactamente por qué, pero si le permite escribir mejor código más rápido, esa es solo la razón para mantenerlos.
Fwiw, acordamos un compromiso de que ponerlos en una línea no hace que esas condiciones previas tan breves no me puedan leer / distraer. P.ej
También señalo que estas condiciones previas introductorias son a menudo declaraciones de flujo de control para el cuerpo (por ejemplo, a
return
), por lo que el miedo a agregar una segunda declaración que esté bajo la misma condición y olvidar escribir llaves es discutible. Una segunda declaración bajo la condición sería un código muerto de todos modos y no tendría sentido.Sospecho que la fluidez en el problema de lectura es causada por el analizador cerebral de la persona que está conectado para tener los frenos como parte de la declaración condicional. Esa no es una representación precisa de la gramática de C ++, pero podría ser un efecto secundario de aprender primero otros lenguajes, donde ese es el caso.
fuente
Después de ver ese video hace un momento, noté que eliminar las llaves hace que sea más fácil ver dónde el código aún debe ser refactorizado. Si necesita llaves, su código probablemente puede ser un poco más limpio.
Dicho esto, cuando estás en un equipo, la eliminación de los aparatos ortopédicos probablemente conducirá a un comportamiento inesperado algún día. Digo quedártelos, y te ahorrarás muchos dolores de cabeza cuando las cosas salgan mal.
fuente
Si su código está bien probado en la unidad , este tipo de "error" explotaría en la cara.
Limpiar el código evitando cualquier paréntesis inútil y feo es una práctica que sigo.
fuente