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 powerManager
y wakeLock
se 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?
Respuestas:
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á
powerManager
en un registro 1 , ya sea que se use o no una variable local, para llamar alnewWakeLock
método. Lo mismo es cierto parawakeLock
. 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.
fuente
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 .
fuente
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.
fuente
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.
fuente
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:
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.
fuente
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:
Compare eso con la versión con variables locales:
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:
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.
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.
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.
fuente
with
declaraciones. Serían convenciones de formato normales en Java.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 :
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.
fuente
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
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.
fuente
Consideremos la Ley de Deméter aquí. En el artículo de Wikipedia sobre LoD se declara lo siguiente:
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:
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
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.
fuente
Una cosa a tener en cuenta es que el código se lee con frecuencia, a diferentes "profundidades". Este código:
es fácil de "descremar". Son 3 declaraciones. Primero se nos ocurre un
PowerManager
. Entonces llegamos a unWakeLock
. Entonces nosotrosacquire
loswakeLock
. 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).
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í:
Ahora esto se comunica con un rápido vistazo "obtener un
WakeLock
, luegoacquire
". Incluso más simple que la primera versión. Es obvio de inmediato que lo que se adquiere es aWakeLock
. Si obtener elPowerManager
es solo un sub-detalle que es bastante insignificante hasta el punto de este código, perowakeLock
es importante, entonces podría ayudar a enterrar elPowerManager
material, 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.
fuente
getSystemService(POWER_SERVICE)
obtiene el administrador de energía..newWakeLock
obtiene una cerradura de estela..acquire
lo adquiere OK, no conozco todos los tipos, pero puedo encontrarlo en el IDE si lo necesito.return
más rápido posible con los métodos, por la misma razón.Esto es incluso un antipatrón con su propio nombre: Train Wreck . Ya se han indicado varias razones para evitar el reemplazo:
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.
fuente
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.
fuente
using(new SQLConnection()) { /* ... */ }
no fuera legal también (si sería útil es un asunto diferente :).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
final
y en C ++ puedes usarconst
. 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.
fuente
getFoo()
. Si evito una declaración local, terminaré conif(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.PowerManager
instancia después de llamar a este método? Déjame comprobar el resto del método ... mmm ok no. Y estaWakeLock
cosa 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.final
es necesario en una variable local en un método, su método es demasiado largo.