¿El uso de nombres de parámetros que difieren de los nombres de tipo solo por la carcasa se considera una mala práctica en C #?

43

Veo preguntas similares a esta con respecto a los nombres de parámetros que coinciden con las propiedades de la clase, pero no puedo encontrar nada con respecto al uso de un nombre de parámetro que sea el mismo que el nombre del tipo de parámetro, excepto por la carcasa en C #. No parece ser una violación que pueda encontrar, pero ¿se considera una mala práctica? Por ejemplo, tengo el siguiente método

public Range PadRange(Range range) {}

Este método toma un rango y devuelve un nuevo rango al que se le ha aplicado algo de relleno. Entonces, dado el contexto genérico, no puedo pensar en un nombre más descriptivo para el parámetro. Sin embargo, recuerdo un consejo que tomé al leer Code Complete sobre "distancia psicológica". Dice

La distancia psicológica se puede definir como la facilidad con la que se pueden diferenciar dos elementos ... Al depurar, prepárese para los problemas causados ​​por una distancia psicológica insuficiente entre nombres de variables similares y entre nombres de rutina similares. A medida que construye el código, elija nombres con grandes diferencias para evitar el problema.

La firma de mi método tiene mucho "Alcance", por lo que parece que puede ser un problema con respecto a esta distancia psicológica. Ahora, veo que muchos desarrolladores hacen lo siguiente

public Range PadRange(Range myRange) {}

Personalmente tengo un fuerte disgusto por esta convención. Agregar un prefijo "my" a nombres de variables no proporciona contexto adicional.

También veo lo siguiente

public Range PadRange(Range rangeToPad) {}

Me gusta más que el prefijo "my", pero en general no me importa. Simplemente se siente demasiado detallado para mí y se lee torpemente como un nombre variable. Para mí, se entiende que el rango se rellenará debido al nombre del método.

Entonces, con todo esto expuesto, mi instinto es ir con la primera firma. Para mí, está limpio. No es necesario forzar el contexto cuando no es necesario. ¿Pero estoy perjudicando a mí mismo o a los futuros desarrolladores con esta convención? ¿Estoy violando una mejor práctica?

Jason Tyler
fuente
35
Si no puede encontrar un parámetro más descriptivo, Range rangeestá bien.
Robert Harvey
21
En esta situación, el IDE coloreará 'Rango' y 'rango' de manera diferente, por lo que es muy fácil ver que uno es el tipo y el otro es un nombre de variable.
17 de 26
10
Sí, lo recuerdo. Está en sus pautas de diseño como una consideración. "CONSIDERA dar a una propiedad el mismo nombre que su tipo". docs.microsoft.com/en-us/dotnet/standard/design-guidelines/…
Jason Tyler
11
También está bien: Range r(al menos para un cuerpo de método corto) y Range toPad.
Bergi
19
Siempre consideré el prefijo "my" como algo que se hace en un código de ejemplo en el que se usa para indicar al lector que un nombre debe cambiarse a otra cosa dependiendo del contexto. No es algo que deba terminar en un código real.
kapex

Respuestas:

100

No pienses demasiado en esto, Range rangeestá bien. Utilizo este tipo de nombres durante más de 15 años en C #, y probablemente mucho más tiempo en C ++, y nunca he tenido ningún inconveniente real, todo lo contrario.

Por supuesto, cuando tiene diferentes variables locales en el mismo alcance, todas del mismo tipo, probablemente sea útil invertir algún esfuerzo mental para distinguirlas adecuadamente.

Doc Brown
fuente
66
Otra excepción que agregaría es cuando la instancia está teniendo una acción particular sobre ella. Hay un poco de espacio para ser más descriptivo de por qué se necesita el parámetro, por ejemplo. Wack (Bozo bozoToBeWacked) Aún más si el parámetro es opcional y describe qué significa el objeto en ese escenario / qué impactará. Mi regla de oro si no es obvio sin mirar el código que hace el parámetro, entonces necesita un mejor nombre y / o comentarios.
Mike
17
Consideraría Wack(Bozo bozoToBeWacked)como un ejemplo de redundancia en el nombre de la variable que se expresa ampliamente por el método en sí mismo (y por lo tanto indeseable según la pregunta original). Wack(Person bozo)Sin embargo, es más semánticamente valioso, ya que implica que se espera que solo se activen los bozos.
Miral
2
En el caso que mencione en el segundo párrafo, a menudo cambiaré el nombre del parámetro a algo como initialRange. Todavía es muy genérico, pero no tiene casi el mismo nivel de desagrado que myRange.
Jaquez
@Miral: se vuelve más relevante en casos como Punch(Bozo punchingBozo, Bozo bozoToBePunched). La nomenclatura detallada es más relevante cuando tiene que distinguir entre varias cosas (que se describen semánticamente con casi las mismas palabras). La sugerencia de OP Range rangeToPadno es necesaria en su ejemplo de método de un parámetro, pero podría ser increíblemente necesario para un método que abarca varios Rangeobjetos.
Flater
77
@Flater Punch(Bozo source, Bozo target)haría el trabajo
Thomas Ayoub
17

Hago esto todo el tiempo, me da mucha tranquilidad. Si se trata de un argumento pasado a un constructor que debe asignarse a un miembro, mi miembro también se denominará rango y la asignación será

this.range = range;

Y normalmente tendría una propiedad llamada Range.

Todos son lo mismo, solo difieren en contexto, por lo que tiene sentido mantener un solo nombre y tendrá que recordar solo un nombre. Es una cosa, las diferencias son puramente técnicas.

Debe ser estricto con los miembros que califiquen completamente con "esto". sin embargo, pero para eso está StyleCop.

Nota lateral de StyleCop

¡Controversia garantizada!

Para aquellos que abogan contra el uso de "esto": he visto _, m, m_ y nada. El lenguaje en sí nos ofrece una forma perfectamente clara, inequívoca y universalmente reconocible de indicar que estamos tratando con un miembro de la clase. ¿Por qué demonios querrías inventar tu propio estilo que mutila nombres ya perfectos?

La única razón por la que puedo pensar es que es un hábito heredado de la era C, cuando en realidad tenía sentido hacerlo porque no había otra manera.

"¡Son más personajes!" ¿Seriamente? "¡El tiempo de compilación se disparará!" ¿Seriamente? "¡Tendré que levantar mi dedo meñique cuando lo escriba!". Como si el tiempo de escritura tuviera algún significado en el tiempo total de desarrollo.

Reconozco que cualquier estilo diferente al que estás acostumbrado generará cierta oposición. Pero usar esto consistentemente es difícil de discutir. Así es como funciona para mí: antes de insertar un nuevo archivo de código, ejecuto StyleCop y encontrará una cantidad de miembros que carecen de "este" calificador. Puse "esto". en el portapapeles, ejecutado por los miembros e insertar. Sin esfuerzo en absoluto.

StyleCop hace mucho más que esto (jaja). Hay muchas maneras en que un desarrollador puede (solo considerando el formato del código) frustrar el trabajo de mantenimiento de su sucesor. StyleCop previene la mayoría de ellos. Es invaluable

Si eres nuevo en esto: generalmente te hace quejarse durante una semana o dos y luego te encantará.

Martin Maat
fuente
19
"Sin embargo, debe ser estricto con los miembros que califican completamente con" esto ", " -1. No usar thisexcepto cuando sea esencial. Es solo ruido de lo contrario. Úselo _rangepara el campo y thisnunca es necesario excepto en los métodos de extensión.
David Arno
12
Estoy de acuerdo con @DavidArno. 'esto' es solo ruido puro. 'Rango' es una propiedad, '_rango' es un campo y 'rango' es un parámetro.
17 de 26
8
@David Si la variable es un miembro de la clase, ES esencial y supera cualquier prefijo arbitrario para indicar que está viendo un miembro de la clase en lugar de un argumento o una variable local.
Martin Maat
66
Mi IDE dispararía bolas de fuego en el segundo en que me asignaría una variable.
Koekje
21
@DavidArno ¿Le gustaría explicar por qué el "ruido" de _es preferible al ruido de this.? Yo diría que uno tiene un significado impuesto por el lenguaje (y generalmente tiene resaltado de sintaxis) mientras que el otro no.
Clint
9

Mi guía personal sobre los métodos, parámetros y variables de denominación es bastante simple:

  1. Si el nombre contiene el tipo que se pasa o devuelve, lo está haciendo mal.
  2. Nombra las cosas por lo que están destinadas, no por lo que son.
  3. Recuerde siempre que el código se lee más de lo que se escribe.

Por lo tanto, la firma óptima del método, en mi opinión, sería:

Range Pad(Range toPad)

Acortar el nombre del método se explica por sí mismo.

El nombre del parámetro toPadle dice inmediatamente al lector que ese parámetro probablemente se modificará en el lugar al rellenarse y luego devolverse. En contraste, no se pueden hacer suposiciones sobre una variable llamada range.

Además, en el cuerpo real del método, cualquier otra Rangevariable que se introduzca se debería (debería) nombrar por su intención, por lo que podría tener paddedy unpadded... toPadcumplir con esas convenciones de nomenclatura, pero rangesimplemente sobresale y no se gelifica.

Ian Kemp
fuente
3
padded/ unpaddedsuena bien para variables locales inmutables. Pero si hay un toPadparámetro mutable , después de que se haya completado el relleno, el nombre toPadya no cabe (a menos que el resultado se devuelva de inmediato). Prefiero seguir Range rangeen esos casos.
kapex
@Kapep Yo lo llamaría solo result. Se modifica y devuelve . El último se desprende del nombre y el primero sigue, ya que devolver un argumento no modificado no tiene sentido.
maaartinus
A partir de la firma, el Padmétodo devuelve a Range. Eso, para mí, implica que el que he pasado se conservará, no se modificará en su lugar, y Rangese devolverá un nuevo relleno . .
Aaron M. Eshbach
1
No estoy seguro de qué pensar de tu consejo. Pad(toPad)se siente un poco mal en mi humilde opinión. Sin embargo, haces un buen punto para defender tu punto de vista. ¡Obtienes un +0 de mi parte! :)
Eric Duminil
En la pregunta dice que "devuelve un nuevo rango al que se le ha aplicado algo de relleno". Estoy de acuerdo con tu nombre para lo que crees que es el escenario, pero para la pregunta real elegiría algo como Range CreateRangeWithPadding (fuente de Range)
Richard Willis
3

Para nombrar elementos de código (tipos, variables, funciones, cualquier cosa), la pregunta clave que debe hacerse es

Si hago un error tipográfico, ¿el compilador lo encontrará por mí?

El peor tipo de error basado en errores tipográficos es aquel en el que el código se compila y se ejecuta, pero proporciona un comportamiento diferente al esperado, por razones sutiles. Y como se debe a un error tipográfico, generalmente es muy difícil de ver cuando inspecciona el código. Si un error tipográfico detendrá la compilación del código, entonces el compilador marcará la línea que causa el problema, y ​​puede encontrarlo y solucionarlo fácilmente.

Para su situación donde el tipo y la variable difieren solo en mayúsculas, este siempre será el caso. (O casi siempre, con suficiente esfuerzo, estoy seguro de que podría hacerlo funcionar, pero realmente tendría que intentarlo). Así que creo que está bien allí.

Debería preocuparse si hubiera dos variables, métodos, funciones o propiedades en el ámbito actual llamado rangey Range. En ese caso, el compilador probablemente lo dejará pasar, y obtendrá un comportamiento inesperado en tiempo de ejecución. Tenga en cuenta que son dos de cualquiera de esos tipos de elementos de código, no solo "dos variables" o "dos funciones", todas ellas pueden ser implícitamente entre sí, con la carnicería resultante cuando se ejecuta. Puede recibir advertencias, pero no puede garantizar nada más que eso. Tiene problemas similares si tenía dos tipos declarados llamados rangey Range.

También tenga en cuenta que lo mismo se aplica al estilo de notación húngara , donde los nombres tienen el prefijo de uno o más caracteres para decir algo más sobre lo que sea. Si tiene una variable llamada Rangey un puntero a ella llamada PRange, es fácil omitir accidentalmente P, por ejemplo. C # debería captar esto, pero C y C ++ solo le darán una advertencia como máximo. O, lo que es más preocupante, suponga que tiene una versión doble llamada DRangey reduce la muestra a una versión flotante llamada FRange. Utilice el flotador por accidente (que es fácil ya que las claves son adyacentes en un teclado) y su código será tipo de trabajo, sino que va a caer otra vez en formas extrañas e impredecibles cuando se ejecuta el proceso de resolución y el underflow.

Ya no estamos en los días en que teníamos límites de nomenclatura de 8 caracteres, o 16 caracteres, o cualquier límite arbitrario. A veces escuché a principiantes quejarse de nombres de variables más largos que hacen que la codificación tarde más. Sin embargo, solo los principiantes se quejan de esto. Los programadores serios saben que lo que realmente lleva tiempo es descubrir errores oscuros, y la mala elección de los nombres es una forma clásica de caer en ese agujero en particular.

Graham
fuente
Solo una nota para los lectores: para C #, las personas realmente deberían evitar la notación húngara. Si bien fue útil en épocas anteriores cuando el resaltado de sintaxis no era una cosa o era limitado, hoy en día realmente no ayuda.
T. Sar - Restablece a Mónica el
@ T.Sar Incluso en el pasado, ¡lo odiaba con pasión! Como usted dice, mejores IDEs han resuelto los problemas a los que estaba dirigido, pero todavía aparece de vez en cuando. Aún lo verá si necesita hablar con la API de Windows, por ejemplo, por razones históricas. No quería criticar por completo los estilos preferidos de las personas si realmente les gusta, pero quería usarlo como un gancho para mostrar que las mayúsculas / minúsculas no son la única forma en que puedes arruinar el nombre.
Graham
Soy consciente de que no estás proponiendo el uso de la notación húngara, pero también soy consciente de que los desarrolladores jóvenes tienen una enorme debilidad por las cosas con nombres geniales. Poder decir "Mi código está escrito en este estilo súper secreto de codificación ninja: ¡la notación húngara!" Puede sonar irresistiblemente genial para las mentes más jóvenes. He visto a demasiados desarrolladores caer presos del bombo de palabras geniales ... La notación húngara es dolor, da la forma del código fuente xX
T. Sar - Restablece a Mónica el
@ T. Sar lo suficientemente cierto. "Los que no recuerdan el pasado están condenados a repetirlo" y todo eso. : /
Graham
1
¿Estamos hablando de la notación húngara original o de cómo fue malinterpretada por Microsoft (cerca de "los escritores de documentación en el equipo de Windows inventaron inadvertidamente lo que se conoció como Sistemas Húngaros" y también en la entrevista de Joel Spolsky por Leo Laporte en el episodio de Triangulación 277, 12/12/2016, 04 minutos 00 segundos - 06 minutos 35 segundos )?
Peter Mortensen
1

Una anécdota que me gustaría agregar, si bien Range rangeesto es sintácticamente legal, podría hacer que las cosas sean más difíciles de depurar o refactorizar. ¿Busca esa variable llamada "rango" en un archivo con muchas variables de tipo Rango? Puede terminar haciendo más trabajo más tarde como resultado de esta elección de nombres.

Sin embargo, esto depende en gran medida del contexto. Si es un archivo de 30 líneas, mis declaraciones realmente no entran en juego.

Jacob M.
fuente
77
La mayoría de las personas usan herramientas que distinguen entre tipos y parámetros o variables, para el desarrollo de Windows. Lo que usted describe me recuerda a los viejos tiempos grep en Unix.
Frank Hileman
1
@FrankHileman Puede sorprenderte, pero Unix todavía está vivo y grep todavía está en uso (: D). Como grep distingue entre mayúsculas y minúsculas, el problema mencionado simplemente no existe. Sin embargo, incluso nosotros, los que odiamos las ventanas adictos a las terminales, rara vez usamos grep para el código fuente, ya que el IDE es mucho mejor en las búsquedas comunes.
maaartinus
Creo que estamos de acuerdo en que la plataforma no es el punto. grepes una gran herramienta, pero no es una herramienta de refactorización. Y existen herramientas de refactorización en cada plataforma de desarrollo que he usado. (OS X, Ubuntu, Windows).
Eric Wilson
@EricWilson En un momento, grep y sed fueron las únicas herramientas de refactorización en Unix.
Frank Hileman
@FrankHileman El hecho de que algo se use como una herramienta de refactorización no significa que sea una. Puedo refactorizar en el bloc de notas, pero eso no lo hace más que un editor de texto.
Eric Wilson
1

Creo que puede usar Range rangehoy en día por una razón: resaltado de sintaxis. Los IDE modernos generalmente resaltan los nombres de los tipos y los nombres de los parámetros en diferentes colores . Además, un tipo y una variable tienen una considerable "distancia lógica" que no debe confundirse fácilmente.

Si este no fuera el caso, consideraría un nombre diferente o trataría de habilitar un complemento / extensión que pueda resaltar esta sintaxis.

akaltar
fuente
0

Cuando una función es genérica, es lógico que los parámetros sean genéricos y, por lo tanto, deben tener nombres genéricos.

No es lo que está diciendo, pero he visto funciones que realizan una función genérica que tiene nombres de parámetros que son engañosamente específicos. Me gusta

public String removeNonDigits(String phoneNumber)

El nombre de la función suena muy genérico, como esto podría aplicarse a muchas cadenas en muchas situaciones. Pero el nombre del parámetro es extrañamente específico, lo que me hace preguntarme si el nombre de la función es engañoso o ... ¿qué?

Entonces, seguro, en lugar de decir Range range, podría decir Range rangeToPad. Pero, ¿qué información agrega esto? Por supuesto, es el rango de relleno. ¿Qué otra cosa podría ser?

Agregar algún prefijo arbitrario, "my" o "m_" o lo que sea, transmite cero información adicional al lector. Cuando he usado idiomas en los que el compilador no permite que un nombre de variable sea el mismo que un nombre de tipo, con o sin mayúsculas y minúsculas, a veces pongo un prefijo o un sufijo, solo para que se compile . Pero eso es solo para satisfacer al compilador. Se podría argumentar que incluso si el compilador puede distinguir, esto hace que sea más fácil para un lector humano distinguir. Pero wow, en Java he escrito declaraciones como "Cliente cliente = nuevo Cliente ();" mil millones de veces y nunca me pareció confuso. (Siempre me ha parecido un poco redundante y prefiero que en VB puedas decir "cliente débil como nuevo cliente" y no tienes que dar el nombre de la clase dos veces).

Donde sí objeto fuertemente a los nombres genéricos es cuando hay dos o más instancias del mismo tipo en la misma función. ESPECIALMENTE parámetros. Me gusta:

public Range pad(Range range1, Range range2)

¿Cuál es la diferencia entre range1 y range2? ¿Cómo se supone que debo saber? Si es algo donde realmente son dos valores genéricos e intercambiables, está bien, como

public boolean overlap(Range range1, Range range2)

Esperaría que devuelva verdadero si los rangos se superponen y falso si no lo hacen, por lo que son genéricos e intercambiables.

Pero si son diferentes, ¡dame una pista de cómo son diferentes! Estaba trabajando en un programa recientemente que tenía una clase de "Lugar" para almacenar datos sobre lugares geográficos, y con variables de este tipo llamadas "p", "lugar", "lugar2", "myPlace", etc. Wow, esos los nombres realmente me ayudan a determinar cuál es cuál.

Arrendajo
fuente