Argumentos nombrados (parámetros) como ayuda de legibilidad

11

Hace mucho tiempo programé mucho en ADA, y era normal nombrar argumentos al invocar una función: SomeObject.DoSomething (SomeParameterName => someValue);

Ahora que C # admite argumentos con nombre, estoy pensando en volver a este hábito en situaciones en las que podría no ser obvio lo que significa un argumento.

Puede argumentar que siempre debería ser obvio lo que significa un argumento, pero si tiene un argumento booleano y las personas que llaman están pasando "verdadero" o "falso", entonces calificar el valor con el nombre hace que el sitio de la llamada sea más legible.

contentFetcher.DownloadNote (nota, manual: verdadero);

Supongo que podría crear Enums en lugar de usar verdadero o falso (Manual, Automático en este caso).

¿Qué piensas de usar ocasionalmente argumentos con nombre para hacer que el código sea más fácil de leer?

Damian
fuente
El comentario de parámetros sobre los métodos también ayuda.
Amir Rezaei
1
@ amir-rezaei: los comentarios de parámetros sobre los métodos solo ayudan si puede confiar en los comentarios. A menos que tenga buenos desarrolladores y buenos procesos de revisión de código, no confiaría en los comentarios.
btilly
Como usuario de Ada por primera vez, estoy para uso ocasional como usted describe. Así es como recuerdo que se usaron en Ada, por cierto, no lo llamaría "anormal", pero la palabra "normal" parece implicar que la mayoría de las llamadas especificarían nombres de parámetros, que no es como recuerdo las cosas. Por supuesto, las convenciones varían, pero el desorden innecesario es una mala convención en cualquier idioma de la OMI.
Steve314
Estoy de acuerdo con su uso en Ada: no fue algo que hicimos todo el tiempo, pero fue útil.
Damian

Respuestas:

7

Esto se sugirió en el desarrollo de C ++, y Stroustrup lo analiza en su "Diseño y evolución de C ++", páginas 153 y siguientes. La propuesta estaba bien formada y se basaba en la experiencia previa con Ada. No fue adoptado.

La razón más importante fue que nadie quería fomentar funciones con un gran número de parámetros. Cada función adicional en un idioma cuesta algo, y no había ningún deseo de agregar una función para facilitar la escritura de programas malos.

También planteó preguntas sobre cuáles eran los nombres de los parámetros canónicos, particularmente en la convención habitual de encabezado y archivo de código. Algunas organizaciones tenían nombres de parámetros más largos y descriptivos en el archivo .h, y nombres más cortos y fáciles de escribir en el archivo .cpp (sufijos de archivos sustitutos, según se desee). Exigir que estos sean los mismos supondría un costo adicional en la compilación, y mezclar los nombres entre los archivos de origen podría causar errores sutiles.

También se puede manejar mediante el uso de objetos en lugar de llamadas a funciones. En lugar de una llamada GetWindow con una docena de parámetros, cree una clase Window con una docena de variables privadas y agregue setters según sea necesario. Al encadenar a los setters, es posible escribir algo así my_window.SetColor(green).SetBorder(true).SetBorderSize(3);. También es posible tener diferentes funciones con diferentes valores predeterminados que llaman a la función que realmente hace el trabajo.

Si solo le preocupa el efecto de la documentación contentFetcher.DownloadNote(note, manual : true);, siempre puede escribir algo así contentFetcher.DownloadNote(note, /* manual */ true);, por lo que ni siquiera es muy útil en la documentación.

David Thornley
fuente
Curiosamente, cuando me mudé de Ada a C, comencé a usar la convención que usted describe; sin embargo, los revisores de código lo odiaban. De acuerdo en no usarlo para grandes cantidades de parámetros.
Damian
7

Creo que se trata de hacer que el código incorrecto sea más legible, en lugar de "mejores prácticas".

Tener un método (o contratista) que tome 20 parámetros es un "mal olor" y es probable que se deba a un problema en su diseño. Sin embargo, si me veo obligado a trabajar en el código cuando los métodos toman muchos parámetros, entonces el parámetro con nombre hace que el código sea menos difícil de entender.

Cuando los métodos solo tienen 1 o 2 parámetros y, por el nombre del método, queda claro cuáles son los parámetros, entonces el parámetro nombrado no agrega nada. Este es el caso ideal para estar.

Si todo el código en el que trabaja está escrito como el libro " código limpio ", entonces tendrá muy poco uso para los parámetros con nombre, sin embargo, vivimos en el mundo real.

Ian
fuente
1
Una función con dos parámetros puede ser confusa si ambos parámetros son del mismo tipo y no tienen idea de cuál es cuál. Por supuesto, puede nombrar la función de una manera que proporcione esa pista, pero en realidad solo está haciendo lo que hacen los nombres de los parámetros, excepto que obliga a incluir esa verbosidad incluso cuando el contexto (por ejemplo, las expresiones que proporcionan parámetros) hacen obvio qué parámetro es cuál.
Steve314
1
@ Steve314 Ejemplo:void TrackDataChange(Data oldData, Data newData)
Alexander
3

Estoy de acuerdo en que agregar el nombre del parámetro lo hace más legible. Sin embargo, la mayoría de los libros que he leído parecen considerar los interruptores booleanos como una mala práctica. A veces hago esto:

public Content DownloadNote(Note note)
{
    return downloadNote(note, manual: false);
}

public Content DownloadNoteManually(Note note)
{
    return downloadNote(note, manual: true);
}

Eso le da más flexibilidad al implementar su API. También le permite controlar el caso en el que tiene varios conmutadores booleanos, pero no todos pueden estar activos al mismo tiempo.

Scott Whitlock
fuente
3
Si tienes x opciones, ¿harás 2 ^ x frontends?
apoorv020
@ apoorv020: si tuviera suficientes parámetros para una llamada al método que 2 ^ x se volviera significativo, crearía una nueva clase para contener los valores de los parámetros y simplemente pasaría un parámetro.
Scott Whitlock
@ scott-whitlock: Opción 1: cree un objeto, establezca x propiedades, llame a un método una vez con su objeto. Opción 2: llame a un método con x parámetros con nombre. Lo que es mejor depende de tu idioma. En un lenguaje de tipo dinámico, la opción 1 requiere significativamente más placa de caldera sin ganancia, y por lo tanto es peor. En un lenguaje tipado estáticamente, aún agrega la repetitiva, pero las pruebas de claves con nombres incorrectos se deben realizar en tiempo de compilación en lugar de tiempo de ejecución. Por lo tanto, la opción 1 es mejor en C #, pero la opción 2 es una clara victoria en Python.
btilly
@btilly: como señaló Ian, Clean Code le dice claramente que no tenga funciones con más de 2 o 3 parámetros. Para ser justos, se trataba de Java, que está estáticamente tipado. El OP también pregunta sobre C #, que está estáticamente escrito. Todavía preferiría usar sobrecargas de funciones y / o nombres de funciones diferentes con nombres precisos que una larga lista de parámetros.
Scott Whitlock
@ scott-whitlock: ¿Estamos realmente en desacuerdo? Estamos de acuerdo en lo que es mejor en C #. Ambos sabemos lo que dice Clean Code. Mi punto fue que es importante entender por qué es bueno, para que sepa cuándo el consejo se ajusta o no a un entorno diferente.
btilly
3

Soy un gran creyente en los parámetros con nombre en situaciones donde los tipos y la semántica no están claros en el nombre del método. Mi experiencia es que pocas personas leen la documentación.

Dicho esto, los parámetros con nombre no deberían ser una alternativa a hacer listas de argumentos razonables, usar objetos auxiliares (para "unir" argumentos relacionados semánticamente) y usar enumeraciones cuando sea relevante.

Uri
fuente
0

Creo que esto es más útil en lenguajes que no son OO, donde puede tener una función que tiene que hacer algo de varias maneras ligeramente diferentes, y la forma en que determina qué hacer se basa en los valores de los parámetros. En el mundo OOP, simplemente sobrecargaríamos la función, pero cuando eso no sea posible, terminarás pasando un montón de banderas (o un montón de valores, y si se pasan o no es la bandera).

Creo que es más legible, hasta cierto punto; pero como otros han mencionado, tener muchos parámetros es un olor a código, por lo que no veo mucho uso para esto en un lenguaje orientado a objetos como C #.

TMN
fuente