¿Deberíamos eliminar las variables locales si podemos?

95

Por ejemplo, para mantener una CPU encendida en Android, puedo usar un código como este:

PowerManager powerManager = (PowerManager)getSystemService(POWER_SERVICE);
WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "abc");
wakeLock.acquire();

pero creo que las variables locales powerManagery wakeLockse pueden eliminar:

((PowerManager)getSystemService(POWER_SERVICE))
    .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakelockTag")
    .acquire();

Aparece una escena similar en la vista de alerta de iOS, por ejemplo: desde

UIAlertView *alert = [[UIAlertView alloc]
    initWithTitle:@"my title"
    message:@"my message"
    delegate:nil
    cancelButtonTitle:@"ok"
    otherButtonTitles:nil];
[alert show];

-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
    [alertView release];
}

a:

[[[UIAlertView alloc]
    initWithTitle:@"my title"
    message:@"my message"
    delegate:nil
    cancelButtonTitle:@"ok"
    otherButtonTitles:nil] show];

-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
    [alertView release];
}

¿Es una buena práctica eliminar una variable local si solo se usa una vez en el alcance?

ggrr
fuente
95
No necesariamente. A veces, hace que el código sea más claro para usar variables de una sola vez, y en la mayoría de los lenguajes de programación decentes, hay muy poco (si alguno) costo de tiempo de ejecución para esas variables adicionales.
Robert Harvey
75
También dificulta el paso por el código con un depurador. Y también debe estar seguro (según el idioma) de que la primera expresión no es NULL o un error.
GrandmasterB
78
No lo es. De hecho, es una buena práctica introducir variables locales para romper cadenas de llamadas a métodos. Es probable que el código de máquina generado sea idéntico, y es casi seguro que el código fuente sea más legible, por lo tanto, mejor.
Kilian Foth
48
Trata eso. Ahora conecte el depurador e intente ver el estado de PowerManager o WakeLock. Date cuenta de tu error. Solía ​​pensar lo mismo ("¿qué pasa con todos estos lugareños?") Hasta que tuve que pasar la mayor parte de mi tiempo investigando el código.
Faerindel
42
Incluso en su ejemplo, su versión "eliminada" tiene una barra de desplazamiento y no cabe en mi pantalla por completo, lo que hace que sea mucho más difícil de leer.
Erik

Respuestas:

235

El código se lee con mucha más frecuencia de lo que está escrito, por lo que debe tener lástima de la pobre alma que tendrá que leer el código dentro de seis meses (puede ser usted) y luchar por el código más claro y fácil de entender. En mi opinión, la primera forma, con variables locales, es mucho más comprensible. Veo tres acciones en tres líneas, en lugar de tres acciones en una línea.

Y si cree que está optimizando algo al deshacerse de las variables locales, no lo está. Un compilador moderno pondrá powerManageren un registro 1 , ya sea que se use o no una variable local, para llamar al newWakeLockmétodo. Lo mismo es cierto para wakeLock. Entonces terminas con el mismo código compilado en cualquier caso.

1 Si tuviera mucho código intermedio entre la declaración y el uso de la variable local, podría ir a la pila, pero es un detalle menor.

Tony BenBrahim
fuente
2
No puede saber si hay mucho código, el optimizador podría incluir algunas funciones ... De lo contrario, de acuerdo, luchar por la legibilidad primero es el movimiento correcto.
Matthieu M.
2
Bueno, pienso lo contrario, si veo que las variables locales se inicializan varias veces en cada función donde se usa en lugar de ser un atributo cuando puede ser, buscaré por qué, básicamente leeré a fondo las líneas y las compararé solo con Asegúrate de que sean lo mismo. Entonces perderé el tiempo.
Walfrat
15
@Walfrat ¿Las variables locales se inicializan varias veces? Ay. Nadie sugirió reutilizar a los locales :)
Luaan
32
Los miembros de @Walfrat generan efectos secundarios y solo deben usarse cuando se desea mantener específicamente el estado entre llamadas a miembros públicos. Esta pregunta parece tratar el uso local para el almacenamiento temporal de cálculos intermedios.
Gusdor
44
P: ¿Deberíamos eliminar las variables locales si podemos? A: No.
Simon
94

Algunos comentarios altamente votados declararon esto, pero ninguna de las respuestas que vi lo hizo, por lo que lo agregaré como respuesta. Su factor principal para decidir este problema es:

Depuración

A menudo, los desarrolladores pasan mucho más tiempo y esfuerzo depurando que escribiendo código.

Con variables locales, puedes:

  • Punto de interrupción en la línea donde está asignado (con todas las demás decoraciones de puntos de interrupción, como puntos de interrupción condicionales, etc.)

  • Inspeccionar / mirar / imprimir / cambiar el valor de la variable local

  • Captura los problemas que surgen debido a los moldes.

  • Tener rastros de pila legibles (la línea XYZ tiene una operación en lugar de 10)

Sin variables locales, todas las tareas anteriores son mucho más difíciles, extremadamente difíciles o francamente imposibles, dependiendo de su depurador.

Como tal, sigue la máxima infame (escribe el código de la misma manera que lo harías como si el próximo desarrollador que lo mantiene después de ti mismo sea un loco loco que sabe dónde vives), y erra por el lado de una depuración más fácil , lo que significa usar variables locales .

DVK
fuente
20
Agregaría que los seguimientos de pila son mucho menos útiles cuando hay muchas llamadas en una sola línea. Si tiene una excepción de puntero nulo en la línea 50 y hay 10 llamadas en esa línea, no limita mucho el vestido. En una aplicación de producción, a menudo será la mayor parte de la información que obtenga de un informe de defectos.
JimmyJames
3
Pasar por el código también es mucho más difícil. Si hay call () -> call () -> call () -> call (), es difícil trabajar en la llamada al tercer método. Mucho más fácil si hay cuatro variables locales
gnasher729
3
@FrankPuffer: tenemos que lidiar con el mundo real. Donde los depuradores no hacen lo que propones.
DVK
2
@DVK: En realidad, hay más depuradores de los que pensé que te permiten inspeccionar o mirar cualquier expresión. MS Visual Studio (desde la versión 2013) tiene esta característica para C ++ y C #. Eclipse lo tiene para Java. En otro comentario, Faerindel mencionó IE11 para JS.
Frank Puffer
44
@DVK: Sí, muchos depuradores del mundo real no hacen lo que les propongo. Pero eso no tiene nada que ver con la primera parte de mi comentario. Me parece una locura suponer que la persona que va a mantener mi código interactuará principalmente con él por medio de un depurador. Los depuradores son excelentes para ciertos propósitos, pero si obtienen la herramienta principal para analizar el código, diría que algo está muy mal y trataría de solucionarlo en lugar de hacer que el código sea más depurable.
Frank Puffer
47

Solo si hace que el código sea más fácil de entender. En sus ejemplos, creo que hace que sea más difícil de leer.

Eliminar las variables en el código compilado es una operación trivial para cualquier compilador respetable. Puede inspeccionar la salida usted mismo para verificar.

como se llame
fuente
1
Eso tiene tanto que ver con el estilo como el uso de variables. La pregunta ya ha sido editada.
Jodrell
29

Su pregunta "¿es una buena práctica eliminar una variable local si solo se usa una vez en el alcance?" está probando los criterios incorrectos. La utilidad de una variable local no depende de la cantidad de veces que se usa, sino de si aclara el código. Etiquetar valores intermedios con nombres significativos puede mejorar la claridad en situaciones como la que presenta, ya que divide el código en fragmentos más pequeños y más digeribles.

En mi opinión, el código no modificado que presentó es más claro que su código modificado y, por lo tanto, no debe modificarse. De hecho, consideraría extraer una variable local de su código modificado para mejorar la claridad.

No esperaría ningún impacto en el rendimiento de las variables locales, e incluso si hay una, es probable que sea demasiado pequeña para que valga la pena considerarla a menos que el código esté en un bucle muy cerrado en una parte crítica de la velocidad del programa.

Jack Aidley
fuente
Creo que eso tiene mucho que ver con el estilo y el uso de espacios en blanco como cualquier cosa. La pregunta ha sido editada.
Jodrell
15

Tal vez.

Personalmente dudaría en eliminar las variables locales si se trata de una conversión de texto. Creo que su versión compacta es menos legible a medida que el número de paréntesis comienza a acercarse al límite mental que tengo. Incluso introduce un nuevo conjunto de paréntesis que no era necesario en la versión un poco más detallada utilizando una variable local.

El resaltado de sintaxis proporcionado por el editor de código podría mitigar tales preocupaciones hasta cierto punto.

A mis ojos, este es el mejor compromiso:

PowerManager powerManager = (PowerManager)getSystemService(POWER_SERVICE);
powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "abc").acquire();

Manteniendo así una variable local y deshaciéndose de la otra. En C #, usaría la palabra clave var en la primera línea ya que el tipo de letra ya proporciona la información de tipo.

9Runa5
fuente
13

Aunque acepto la validez de las respuestas que favorecen las variables locales, voy a jugar al abogado del diablo y presentar una visión contraria.

Personalmente, estoy un poco en contra del uso de variables locales únicamente para propósitos de documentación, aunque esa razón en sí misma indica que la práctica tiene valor: las variables locales efectivamente seudodocumentan el código.

En su caso, el problema principal es la sangría y no la ausencia de variables. Podría (y debería) formatear el código de la siguiente manera:

((PowerManager)getSystemService(POWER_SERVICE))
        .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"MyWakelockTag")
        .acquire();

Compare eso con la versión con variables locales:

PowerManager powerManager=(PowerManager)getSystemService(POWER_SERVICE);
WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"abc");
wakeLock.acquire();

Con las variables locales: los nombres agregan información al lector y los tipos están claramente especificados, pero las llamadas a métodos reales son menos visibles y (en mi opinión) no se leen tan claramente.

Sin usar variables locales: es más conciso y las llamadas al método son más visibles, pero puede solicitar más información sobre lo que se devuelve. Sin embargo, algunos IDEs pueden mostrarle esto.

Tres comentarios más:

  1. En mi opinión, agregar código que no tiene un uso funcional a veces puede ser confuso ya que el lector debe darse cuenta de que en realidad no tiene un uso funcional y simplemente está ahí para "documentación". Por ejemplo, si este método tuviera 100 líneas de longitud, no sería obvio que las variables locales (y, por lo tanto, el resultado de la llamada al método) no fueran necesarias en algún momento posterior, a menos que lea el método completo.

  2. Agregar las variables locales significa que debe especificar sus tipos, y esto introduce una dependencia en el código que de otro modo no estaría allí. Si el tipo de retorno de los métodos cambiara trivialmente (por ejemplo, se le cambió el nombre), tendría que actualizar su código, mientras que sin las variables locales no lo haría.

  3. La depuración podría ser más fácil con variables locales si su depurador no muestra los valores devueltos por los métodos. Pero la solución para eso es corregir las deficiencias en los depuradores, no cambiar el código.

rghome
fuente
Con respecto a sus comentarios adicionales: 1. Esto no debería ser un problema si sigue la convención de que las variables locales se declaran lo más cerca posible de donde se usan y mantiene sus métodos a una longitud razonable. 2. No en un lenguaje de programación con inferencia de tipos. 3. El código bien escrito a menudo no necesita un depurador en absoluto.
Robert Harvey
2
Su primer ejemplo de código solo funciona si está creando sus objetos utilizando interfaces fluidas o un "generador", patrones que no usaría en todas partes en mi código, sino solo de forma selectiva.
Robert Harvey
1
Creo que la pregunta supone que las variables locales son funcionalmente redundantes y, por lo tanto, ese tipo de interfaz es necesaria para el caso. Probablemente podríamos lograr eliminar a los locales si fuera de otra manera a través de varias contorsiones, pero tenía en mente que estábamos viendo el caso simple.
rghome
1
Encuentro su variante aún peor para la legibilidad. Es posible que haya estado expuesto demasiado a VB.net, pero mi primer pensamiento al ver su muestra es "¿A dónde se fue la declaración WITH? ¿La eliminé accidentalmente?" Necesito mirar dos veces lo que está sucediendo y eso no es bueno cuando necesito revisar el código muchos meses después.
Tonny
1
@Tonny para mí, es más legible: los locales no agregan nada que no sea obvio por el contexto. Tengo mi Java de frente, así que no hay withdeclaraciones. Serían convenciones de formato normales en Java.
rghome
6

Hay una tensión de motivaciones aquí. La introducción de variables temporales puede hacer que el código sea más fácil de leer. Pero también pueden prevenir, y hacer que sea más difícil de ver, otras posibles refactorizaciones, como el Método de extracción y Reemplazar temp con consulta . Estos últimos tipos de refactorizaciones, cuando corresponde, a menudo proporcionan beneficios mucho mayores que la variable temporal.

Sobre las motivaciones para estas últimas refactorizaciones, Fowler escribe :

"El problema con las temperaturas es que son temporales y locales. Debido a que solo se pueden ver en el contexto del método en el que se usan, las temperaturas tienden a fomentar métodos más largos, porque esa es la única forma en que se puede alcanzar la temperatura. reemplazando la temperatura con un método de consulta, cualquier método en la clase puede obtener la información. Eso ayuda mucho a encontrar un código más limpio para la clase ".

Entonces, sí, use temporales si hacen que el código sea más legible, especialmente si esa es una norma local para usted y su equipo. Pero tenga en cuenta que hacerlo a veces puede hacer que sea más difícil detectar mejoras alternativas más grandes. Si puede desarrollar su capacidad de sentir cuándo vale la pena quedarse sin esas temperaturas y sentirse más cómodo al hacerlo, entonces probablemente sea algo bueno.

FWIW Personalmente evité leer el libro de Fowler "Refactorización" durante diez años porque imaginé que no había mucho que decir sobre temas tan relativamente sencillos. Estaba completamente equivocado Cuando finalmente lo leí, cambió mis prácticas diarias de codificación, para mejor.

Jonathan Hartley
fuente
1
Gran respuesta. El mejor código que he escrito (y he visto de otros) a menudo tenía muchos métodos pequeños (2, 3 líneas) que podrían reemplazar a tales variables temporales. Relacionada está esta toma controvertida que los métodos privados apestan ... Bien pensado y a menudo lo he encontrado cierto.
Stijn de Witt
Las temperaturas en esta pregunta ya se refieren a funciones, por lo que esta respuesta es irrelevante para la pregunta de OP.
user949300
@ user949300 No creo que sea irrelevante. Sí, las temperaturas en el ejemplo específico del OP son los valores de retorno de funciones o métodos. Pero el OP es muy claro y es solo un escenario de ejemplo. La pregunta real es mucho más general: "¿deberíamos eliminar las variables temporales cuando podamos?"
Jonathan Hartley
1
OK, estoy vendido, ** intenté ** cambiar mi voto. Pero a menudo, cuando voy más allá del alcance limitado de la pregunta de OP, me critican. SO puede ser voluble ... :-). Er, no puedo cambiar mi voto hasta que edites, lo que sea ...
user949300
@ user949300 ¡Santa vaca! ¡Una persona que cambia de opinión al considerar cuidadosamente los problemas! Usted, señor, es una rareza, y me quito la gorra.
Jonathan Hartley
3

Bueno, es una buena idea eliminar las variables locales si puede hacer que el código sea más legible. Esa larga línea tuya no es legible, pero sigue un estilo OO bastante detallado. Si pudieras reducirlo a algo como

acquireWakeLock(POWER_SERVICE, PARTIAL, "abc");

entonces diría que probablemente sería una buena idea. Quizás pueda introducir métodos de ayuda para reducirlo a algo similar; Si un código como este aparece varias veces, entonces podría valer la pena.

a la izquierda
fuente
2

Consideremos la Ley de Deméter aquí. En el artículo de Wikipedia sobre LoD se declara lo siguiente:

La Ley de Demeter para funciones requiere que un método m de un objeto O solo invoque los métodos de los siguientes tipos de objetos: [2]

  1. O mismo
  2. parámetros de m
  3. Cualquier objeto creado / instanciado dentro de m
  4. Objetos componentes directos de O
  5. Una variable global, accesible por O, en el alcance de m

Una de las consecuencias de seguir esta Ley es que debe evitar invocar métodos de objetos devueltos por otros métodos en una cadena larga punteada, como se muestra en el segundo ejemplo anterior:

((PowerManager)getSystemService(POWER_SERVICE)).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"MyWakelockTag").acquire();

Es realmente difícil descubrir qué está haciendo esto. Para comprenderlo, debe comprender qué hace cada procedimiento y luego descifrar qué función se llama en cada objeto. El primer bloque de código

PowerManager powerManager=(PowerManager)getSystemService(POWER_SERVICE);
WakeLock wakeLock=powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"abc");
wakeLock.acquire();

muestra claramente lo que está tratando de hacer: obtiene un objeto PowerManager, obtiene un objeto WakeLock del PowerManager y luego adquiere el wakeLock. Lo anterior sigue la regla # 3 de LoD: está creando instancias de estos objetos dentro de su código y, por lo tanto, puede usarlos para hacer lo que necesita.

Quizás otra forma de pensar es recordar que al crear software debe escribir por claridad, no por brevedad. El 90% de todo el desarrollo de software es mantenimiento. Nunca escriba un código que no le gustaría mantener.

La mejor de las suertes.

Bob Jarvis
fuente
3
Me interesaría cómo encaja la sintaxis fluida en esta respuesta. Con el formato correcto, la sintaxis fluida es altamente legible.
Gusdor
12
Eso no es lo que significa "Ley de Deméter". La Ley de Deméter no es un ejercicio de conteo de puntos; esencialmente significa "solo habla con tus amigos inmediatos".
Robert Harvey
55
Acceder a los mismos métodos y miembros a través de una variable intermedia sigue siendo una violación tan grave de la ley de Demeter. Lo has oscurecido, no lo has arreglado.
Jonathan Hartley
2
En términos de la "Ley de Deméter", ambas versiones son igualmente "malas".
Hulk
@Gusdor estuvo de acuerdo, esto es más un comentario sobre el estilo en el ejemplo de la pregunta. La pregunta ya ha sido editada.
Jodrell
2

Una cosa a tener en cuenta es que el código se lee con frecuencia, a diferentes "profundidades". Este código:

PowerManager powerManager = (PowerManager)getSystemService(POWER_SERVICE);
WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "abc");
wakeLock.acquire();

es fácil de "descremar". Son 3 declaraciones. Primero se nos ocurre un PowerManager. Entonces llegamos a un WakeLock. Entonces nosotros acquirelos wakeLock. Puedo ver eso fácilmente con solo mirar el comienzo de cada línea; las asignaciones de variables simples son realmente fáciles de reconocer parcialmente como "Tipo varName = ..." y solo se pasa por alto mentalmente el "...". De manera similar, la última declaración obviamente no es la forma de la tarea, sino que solo involucra dos nombres, por lo que la "esencia principal" es evidente de inmediato. A menudo, eso es todo lo que necesitaría saber si solo estuviera tratando de responder "¿qué hace este código?" a un nivel alto.

Si estoy persiguiendo un error sutil que creo que está aquí, entonces obviamente tendré que repasar esto con mucho más detalle, y realmente recordaré el "..." s. Pero la estructura de declaración separada todavía me ayuda a hacer esa declaración a la vez (especialmente útil si necesito profundizar en la implementación de las cosas que se llaman en cada declaración; cuando regreso, entiendo completamente "una unidad" y luego puede pasar a la siguiente declaración).

((PowerManager)getSystemService(POWER_SERVICE))
    .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakelockTag")
    .acquire();

Ahora es todo una declaración. La estructura de nivel superior no es tan fácil de leer; En la versión original del OP, sin saltos de línea y sangría para comunicar visualmente cualquier estructura, habría tenido que contar paréntesis para decodificarlo en una secuencia de 3 pasos. Si algunas de las expresiones de varias partes están anidadas entre sí en lugar de estar dispuestas como una cadena de llamadas a métodos, entonces podría parecer similar a esto, por lo que tengo que tener cuidado al confiar en eso sin contar paréntesis. Y si confío en la sangría y solo paso rápidamente a lo último como el supuesto punto de todo esto, ¿qué .acquire()me dice por sí solo?

Sin embargo, a veces, eso puede ser lo que quieres. Si aplico su transformación a mitad de camino y escribí:

WakeLock wakeLock =
     ((PowerManeger)getSystemService(POWER_SERVICE))
    .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLockTage");
wakeLock.acquire();

Ahora esto se comunica con un rápido vistazo "obtener un WakeLock, luego acquire". Incluso más simple que la primera versión. Es obvio de inmediato que lo que se adquiere es a WakeLock. Si obtener el PowerManageres solo un sub-detalle que es bastante insignificante hasta el punto de este código, pero wakeLockes importante, entonces podría ayudar a enterrar el PowerManagermaterial, por lo que es natural pasarlo por alto si solo está tratando de obtener rápidamente un idea de lo que hace este código. Y no nombrar que se comunica que se sólo se utiliza una vez, ya veces eso es lo que es importante (si el resto del alcance es muy largo, tendría que leer todo eso para saber si alguna vez se volvió a usar; aunque usar sub-ámbitos explícitos puede ser otra forma de abordar eso, si su idioma los admite).

Lo que saca a relucir que todo depende del contexto y de lo que desea comunicar. Al igual que con la escritura en prosa en lenguaje natural, siempre hay muchas formas de escribir una determinada pieza de código que son básicamente equivalentes en términos de contenido de información. Al igual que con la escritura en prosa en lenguaje natural, la forma de elegir entre ellos generalmente no debería ser aplicar reglas mecanicistas como "eliminar cualquier variable local que solo ocurra una vez". Más bien cómoSi elige escribir su código, enfatizará ciertas cosas y desestimará otras. Debe esforzarse por tomar esas decisiones conscientemente (incluida la opción de escribir código menos legible por razones técnicas a veces), en función de lo que realmente desea enfatizar. Piensa especialmente en lo que servirá a los lectores que solo necesitan "entender la esencia" de tu código (en varios niveles), ya que eso sucederá con mucha más frecuencia que una lectura muy cercana de expresión por expresión.

Ben
fuente
Para mí, aunque no conozco la API, es muy obvio lo que hace el código, incluso sin las variables. getSystemService(POWER_SERVICE)obtiene el administrador de energía. .newWakeLockobtiene una cerradura de estela. .acquirelo adquiere OK, no conozco todos los tipos, pero puedo encontrarlo en el IDE si lo necesito.
rghome
Puede ser obvio para usted lo que se supone que debe hacer el código , pero no tiene idea de lo que realmente hace. Si estoy buscando un error, todo lo que sé es que algún código en algún lugar no hace lo que se supone que debe hacer, y tengo que encontrar qué código.
gnasher729
@ gnasher729 Sí. La búsqueda de errores fue un ejemplo que di cuando necesitarías leer cuidadosamente todos los detalles. Y una de las cosas que realmente ayuda a encontrar el código que no está haciendo lo que se supone que debe hacer es poder ver fácilmente cuál era la intención del autor original.
Ben
cuando vuelvo he entendido completamente "una unidad" y luego puedo pasar a la siguiente declaración. En realidad no. De hecho, las variables locales impiden esa comprensión completa. Debido a que aún persisten ... ocupan espacio mental ... lo que les sucederá en las próximas 20 declaraciones ... redoble de tambores ... Sin los locales, estarías seguro de que los objetos se habían ido e imposibles de hacer nada con ellos en las siguientes líneas. No hay necesidad de recordar sobre ellos. Me gusta lo returnmás rápido posible con los métodos, por la misma razón.
Stijn de Witt
2

Esto es incluso un antipatrón con su propio nombre: Train Wreck . Ya se han indicado varias razones para evitar el reemplazo:

  • Mas dificil de leer
  • Más difícil de depurar (tanto para ver variables como para detectar ubicaciones de excepciones)
  • Violación de la Ley de Demeter (LoD)

Considere si este método sabe demasiado de otros objetos. El método de encadenamiento es una alternativa que podría ayudarlo a reducir el acoplamiento.

También recuerde que las referencias a objetos son realmente baratas.

Borjab
fuente
Ehm, ¿el código revisado no está encadenando métodos? EDITAR lee el artículo vinculado, así que ahora veo la diferencia. Muy buen artículo gracias!
Stijn de Witt
Gracias por revisarlo. De todos modos, el encadenamiento de métodos puede funcionar en algunos casos, mientras que simplemente dejar la variable puede ser la decisión adecuada. Siempre es bueno saber por qué las personas no están de acuerdo con su respuesta.
Borjab
Supongo que lo contrario de "Train Wreck" es "Local Line". Es ese tren entre dos ciudades principales que se detiene en cada aldea rural en el medio en caso de que alguien quiera subir o bajar, aunque la mayoría de los días nadie lo hace.
Rghome
1

La pregunta planteada es "¿Deberíamos eliminar las variables locales si podemos"?

No, no debes eliminar solo porque puedes.

Debe seguir las pautas de codificación en su tienda.

En su mayor parte, las variables locales hacen que el código sea más fácil de leer y depurar.

Me gusta lo que hiciste con PowerManager powerManager. Para mí, una minúscula de la clase significa que solo se usa una vez.

Cuando no debería, es si la variable va a retener recursos costosos. Muchos idiomas tienen sintaxis para una variable local que necesita ser limpiada / liberada. En C # está usando.

using(SQLconnection conn = new SQLconnnection())
{
    using(SQLcommand cmd = SQLconnnection.CreateCommand())
    {
    }
}
paparazzo
fuente
Esto no está realmente relacionado con las variables locales sino con la limpieza de recursos ... No estoy muy versado en C #, pero me sorprendería si using(new SQLConnection()) { /* ... */ }no fuera legal también (si sería útil es un asunto diferente :).
Stijn de Witt
1

Un aspecto importante no se ha mencionado en las otras respuestas: cada vez que agrega una variable, introduce un estado mutable. Esto suele ser algo malo porque hace que su código sea más complejo y, por lo tanto, más difícil de comprender y probar. Por supuesto, cuanto menor es el alcance de la variable, menor es el problema.

Lo que quiere en realidad no es una variable cuyo valor pueda modificarse sino una constante temporal. Por lo tanto, considere expresar esto en su código si su idioma lo permite. En Java puedes usar finaly en C ++ puedes usar const. En la mayoría de los lenguajes funcionales, este es el comportamiento predeterminado.

Es cierto que las variables locales son el tipo menos dañino de estado mutable. Las variables miembro pueden causar muchos más problemas y las variables estáticas son aún peores. Aún así, me parece importante expresar con la mayor precisión posible en su código lo que se supone que debe hacer. Y hay una gran diferencia entre una variable que podría modificarse más adelante y un simple nombre para un resultado intermedio. Entonces, si su idioma le permite expresar esta diferencia, simplemente hágalo.

Frank Puffer
fuente
2
No desestimé su respuesta, pero supongo que está relacionada con el hecho de que las variables locales generalmente no se consideran 'estado' en lenguajes imperativos a menos que esté hablando de algún tipo de método de larga duración. Estoy de acuerdo con el uso de final / const como una mejor práctica, pero es bastante improbable que la introducción de una variable para simplemente romper una llamada encadenada conduzca a problemas causados ​​por un estado mutable. De hecho, el uso de variables locales ayuda a lidiar con el estado mutable. Si un método puede devolver diferentes valores en diferentes momentos, de lo contrario puede terminar con algunos errores realmente interesantes.
JimmyJames
@JimmyJames: He agregado alguna explicación a mi respuesta. Pero hay una parte de su comentario que no entendí: "el uso de variables locales ayuda a lidiar con el estado mutable". ¿Podrías explicar esto?
Frank Puffer
1
Por ejemplo, digamos que necesito verificar un valor y si es más de 10 disparar una alerta. Supongamos que este valor proviene del método getFoo(). Si evito una declaración local, terminaré con if(getFoo() > 10) alert(getFoo());Pero getFoo () podría devolver valores diferentes en las dos llamadas diferentes. Podría enviar una alerta con un valor menor o igual a 10 que es confuso en el mejor de los casos y volverá a mí como un defecto. Este tipo de cosas se vuelve más importante con la concurrencia. La asignación local es atómica.
JimmyJames
Muy buen punto. Tal vez la razón por la que no me gustan estos locales ... ¿Vas a hacer algo con esa PowerManagerinstancia después de llamar a este método? Déjame comprobar el resto del método ... mmm ok no. Y esta WakeLockcosa que tienes ... ¿qué estás haciendo con eso (escaneando el resto del método una vez más) ... mmm otra vez nada ... ok, entonces ¿por qué están allí? Oh sí, se supone que es más legible ... pero sin ellos, estoy seguro de que ya no los usarás, así que no tengo que leer el resto del método.
Stijn de Witt
En una charla reciente, el orador argumentó que la mejor manera de mostrar que una variable es final es escribir métodos cortos donde sea obvio que la variable no cambia . Si finales necesario en una variable local en un método, su método es demasiado largo.
user949300