Código limpio: funciones con pocos parámetros [cerrado]

49

Leí los primeros capítulos de Clean Code de Robert C. Martin, y me parece que es bastante bueno, pero tengo una duda, en una parte se menciona que es bueno (cognitivamente) que las funciones tengan pocos parámetros. como sea posible, incluso sugiere que 3 o más parámetros son demasiado para una función (lo cual me parece muy exagerado e idealista), así que comencé a preguntarme ...

Las prácticas de usar variables globales y pasar muchos argumentos sobre las funciones serían malas prácticas de programación, pero el uso de variables globales puede reducir en gran medida el número de parámetros en las funciones ...

Entonces quería escuchar lo que piensas al respecto, ¿vale la pena usar variables globales para reducir el número de parámetros de las funciones o no? ¿En qué casos sería?

Lo que creo es que depende de varios factores:

  • Tamaño del código fuente.
  • Número de parámetros en promedio de las funciones.
  • Numero de funciones.
  • Frecuencia en la que se usan las mismas variables.

En mi opinión, si el tamaño del código fuente es relativamente pequeño (como menos de 600 líneas de código), hay muchas funciones, las mismas variables se pasan como parámetros y las funciones tienen muchos parámetros, entonces valdría la pena usar variables globales, pero yo quisiera saber ...

  • ¿Compartes mi opinión?
  • ¿Qué opinas de otros casos en los que el código fuente es más grande, etc.?

PS . Vi esta publicación , los títulos son muy similares, pero él no me pregunta qué quiero saber.

OiciTrap
fuente
144
No creo que la alternativa sea global, sino consolidar argumentos en objetos. Probablemente sea más una sugerencia de la que postLetter(string country, string town, string postcode, string streetAddress, int appartmentNumber, string careOf)es una versión maloliente postLetter(Address address). Continúa leyendo el libro, ojalá diga algo así.
Nathan Cooper
3
@DocBrown Tomé la pregunta como algo más parecido a lo que el tío Bob dice que no use más de 3 parámetros, así que soluciono ese problema usando variables globales, ¿verdad? :-) Creo que es probable que el autor no sepa que hay mejores formas de solucionar este problema, como se menciona en las respuestas a continuación.
bytedev
99
No más de n parámetros es una regla general (para cualquier valor de n), no grabada en un diamante. No confundas los buenos consejos con un mandato. Muchos parámetros son generalmente un olor a código que tienes demasiado en una función / método. La gente solía evitar dividirse en múltiples funciones para esquivar la sobrecarga adicional de las llamadas adicionales. Pocas aplicaciones son tan intensivas en rendimiento y un generador de perfiles puede decirle cuándo y dónde debe evitar llamadas adicionales.
Jared Smith
14
Esto muestra lo que está mal con este tipo de regla libre de juicio: abre la puerta a 'soluciones' libres de juicio. Si una función tiene muchos argumentos, puede indicar un diseño subóptimo, generalmente no solo de la función, sino también del contexto en el que se está utilizando. La solución (si es necesario) es buscar refactorizar el código. No puedo darle una regla simple, general y libre de juicio sobre cómo hacerlo, pero eso no significa que 'no más que N argumentos' sea una buena regla.
sdenham
44
Si tiene demasiados parámetros para una función, las probabilidades son algunas de ellas relacionadas y deben agruparse en un objeto que luego se convierte en un único parámetro que encapsula múltiples datos. Hay una tercera opción aquí.

Respuestas:

113

No comparto tu opinión. En mi opinión, usar variables globales es una práctica peor que más parámetros, independientemente de las cualidades que describió. Mi razonamiento es que más parámetros pueden hacer que un método sea más difícil de entender, pero las variables globales pueden causar muchos problemas para el código, incluida una capacidad de prueba deficiente, errores de concurrencia y un acoplamiento estrecho. No importa cuántos parámetros tenga una función, no tendrá inherentemente los mismos problemas que las variables globales.

... se pasan las mismas variables como parámetros

Se puede ser un olor diseño. Si tiene los mismos parámetros que se pasan a la mayoría de las funciones en su sistema, puede haber una preocupación transversal que debería manejarse mediante la introducción de un nuevo componente. No creo que pasar la misma variable a muchas funciones sea un buen razonamiento para introducir variables globales.

En una edición de su pregunta, indicó que la introducción de variables globales podría mejorar la legibilidad del código. Estoy en desacuerdo. El uso de variables globales está oculto en el código de implementación, mientras que los parámetros de función se declaran en la firma. Las funciones deberían ser idealmente puras. Solo deben operar según sus parámetros y no deben tener efectos secundarios. Si tiene una función pura, puede razonar sobre la función mirando solo una función. Si su función no es pura, debe considerar el estado de otros componentes, y se hace mucho más difícil razonar.

Samuel
fuente
Ok, es bueno escuchar otras opiniones, pero sobre el olor del diseño , estoy programando problemas en C que se resuelven mediante métodos de inteligencia artificial y tiendo a usar muchas funciones que casi siempre usan las mismas matrices, matrices o variables (que Paso como parámetros a las funciones), digo esto porque no creo que pueda poner estas variables dentro de un concepto / cosa común como una estructura o unión, por lo que no sabría cómo hacer un mejor diseño, Por eso creo que el uso de variables globales en este caso podría valer la pena, pero lo más probable es que me equivoque.
OiciTrap
1
Eso no suena como un problema de diseño. Sigo pensando que pasar parámetros a las funciones es el mejor diseño. En un sistema de inteligencia artificial como el que estás describiendo, sería útil escribir pruebas unitarias para probar las partes del sistema, y ​​la forma más fácil de hacerlo es con parámetros.
Samuel
96
Más parámetros hacen que una subrutina sea más difícil de entender, las variables globales hacen que todo el programa, es decir, todas las subrutinas sean más difíciles de entender.
Jörg W Mittag
2
Mantengo una base de código donde algunas de las funciones toman más de una docena de parámetros. Es una gran pérdida de tiempo: cada vez que necesito llamar a la función, necesito abrir ese archivo en otra ventana para saber en qué orden deben especificarse los parámetros. Si usara un IDE que me diera algo como intellisense o si usara un lenguaje que hubiera nombrado parámetros, entonces no sería tan malo, pero ¿quién puede recordar en qué orden están una docena de parámetros para todas esas funciones?
Jerry Jeremiah
66
La respuesta es correcta en lo que dice, sin embargo, parece que da por sentado el malentendido de los OP sobre las recomendaciones en "Código limpio". Estoy seguro de que no hay ninguna recomendación para reemplazar los parámetros de función por globales en ese libro.
Doc Brown
68

Debe evitar variables globales como la peste .

No voy a poner un límite difícil de número de argumentos (como 3 o 4), pero que no desee mantener al mínimo, si es posible.

Use structs (u objetos en C ++) para agrupar variables en una sola entidad y pasar eso (por referencia) a las funciones. Por lo general, una función obtiene una estructura u objeto (con algunas cosas diferentes) que se le pasa junto con un par de otros parámetros que le indican a la función que le haga algo struct.

Para un código modular, limpio y de buen olor, intente atenerse al principio de responsabilidad única . Haga eso con sus estructuras (u objetos), las funciones y los archivos de origen. Si hace eso, el número natural de parámetros pasados ​​a una función será obvio.

robert bristow-johnson
fuente
55
¿Cuál es la diferencia principal entre pasar decenas de parámetros ocultos en una estructura y pasarlos explícitamente?
Ruslan
21
@Ruslan Cohesión.
abuzittin gillifirca
99
Y es más probable que refactorice la función en funciones más pequeñas, ya que puede pasar un parámetro a las subfunciones en lugar de decenas de parámetros. Y menos riesgo de mezclar los parámetros si usa argumentos posicionales.
Hans Olsson
8
Está bien, pero debe garantizar la coherencia en los Structs: asegúrese de que los parámetros agrupados en un Struct estén 'relacionados'. Puede usar más de un Struct en algunas circunstancias.
Andrew Dodds
8
@abuzittingillifirca No obtienes cohesión automáticamente. Si la única justificación para poner parámetros en una estructura es pasarlos a una función particular, entonces la cohesión es probablemente ilusoria.
sdenham
55

Estamos hablando de carga cognitiva, no de sintaxis. Entonces la pregunta es ... ¿Qué es un parámetro en este contexto?

Un parámetro es un valor que afecta el comportamiento de la función. Cuantos más parámetros, más combinaciones posibles de valores obtenga, más difícil será el razonamiento sobre la función.

En ese sentido, las variables globales que utiliza la función son parámetros. Son parámetros que no aparecen en su firma, que tienen problemas de orden de construcción, control de acceso y remanencia.

A menos que dicho parámetro sea lo que se llama una preocupación transversal , es decir, un estado de todo el programa que todo usa pero nada altera (por ejemplo, un objeto de registro), no debe reemplazar los parámetros de función con variables globales. Seguirían siendo parámetros, pero más desagradables.

Quentin
fuente
11
Para ti un +1, ya sea un inodoro o un inodoro, apestan igual. Buen trabajo señalando al lobo con piel de cordero.
Jared Smith
1
+1 por afirmar que tanto parms como vars globales son malos. Pero quiero aclarar algo. En la mayoría de los lenguajes, los parámetros primitivos se pasan por valor de forma predeterminada (Java), y en otros puede pasarlos por valor explícitamente (PL / SQL). Por otro lado, siempre se accede a las primitivas globales por referencia (por así decirlo). Por lo tanto, los parámetros, al menos de los tipos primitivos, siempre son más seguros que las variables globales. Aunque, por supuesto, tener más de dos o tres parámetros es un olor, y tener doce parámetros es un gran olor que debe ser refactorizado.
Tulains Córdova
44
Absolutamente, una variable global ES un parámetro oculto.
Bill K
+1 A su punto, he visto simulaciones de MATLAB que se basan en variables globales para pasar datos. El resultado era completamente ilegible porque era muy difícil saber qué variables eran parámetros para qué función.
Cort Ammon
34

En mi humilde opinión, su pregunta se basa en un malentendido. En "Código limpio", Bob Martin no sugiere reemplazar los parámetros de funciones repetidas por globales, eso sería un consejo realmente horrible. Sugiere reemplazarlos por variables miembro privadas de la clase de la función. Y también propone clases pequeñas y coherentes (generalmente más pequeñas que las 600 líneas de código que mencionó), por lo que estas variables miembro definitivamente no son globales.

Entonces, cuando tiene la opinión en un contexto con menos de 600 líneas "valdría la pena usar variables globales" , entonces comparte perfectamente la opinión del tío Bob. Por supuesto, es discutible si "3 parámetros como máximo" es el número ideal, y si esta regla a veces conduce a demasiadas variables miembro incluso en clases pequeñas. En mi humilde opinión, esto es una compensación, no hay una regla estricta donde dibujar la línea.

Doc Brown
fuente
10
Nunca entendí por qué alguien preferiría que su clase tuviera estado introduciendo parámetros en un constructor en lugar de simplemente vivir con un argumento real. Esto siempre me pareció un enorme aumento en la complejidad. (Un ejemplo de la vida real que he visto de esto es un objeto de conexión a la base de datos, que hizo casi imposible tratar de rastrear el estado de la base de datos a través del programa cuando se combina con la inyección de dependencia). Pero quizás Clean Code tiene más que decir sobre ese particular tema. Los globales son, por supuesto, una opción aún peor en lo que respecta a hacer las cosas con estado.
jpmc26
2
@ jpmc26: uno solo obtiene un "enorme aumento de complejidad" si las clases se vuelven demasiado grandes y obtienen demasiadas variables miembro, por lo que el resultado ya no es coherente.
Doc Brown
44
Creo que esa respuesta ignora la dificultad en la gestión del estado (que incluso podría ser mutable) que se extiende a través de muchas clases. Cuando una función depende no solo de los argumentos, sino también de cómo se construyó el objeto (o incluso se modificó durante su vida útil), entender su estado actual cuando realiza una llamada en particular se vuelve más difícil. Ahora tiene que rastrear la construcción de otro objeto, solo para descubrir qué hará la llamada. Agregar variables de instancia aumenta activamente la cantidad de estado del programa, a menos que construya el objeto y lo deseche de inmediato.
jpmc26
3
@ jpmc26 Un patrón que uso regularmente cuando refactorizo ​​es que el constructor actúa como establecer un contexto, luego los argumentos del método son específicos de una acción. El objeto no es exactamente con estado, porque el estado que contiene nunca cambia, pero mover esas acciones comunes a los métodos de este contenedor mejora significativamente la legibilidad donde se usa (el contexto solo se establece una vez, similar a los administradores de contexto de Python), y reduce la duplicación si Se realizan múltiples llamadas a los métodos del objeto.
Izkata
3
+1 Por decir claramente que las variables miembro no son variables globales. Mucha gente piensa que lo son.
Tulains Córdova
34

Tener muchos parámetros se considera indeseable, pero convertirlos en campos o variables globales es mucho peor porque no resuelve el problema real sino que introduce nuevos problemas.

Tener muchos parámetros no es en sí mismo el problema, pero es un síntoma de que podría tener un problema. Considere este método:

Graphics.PaintRectangle(left, top, length, height, red, green, blue, transparency);

Tener 7 parámetros es una señal de advertencia definitiva. El problema subyacente es que estos parámetros no son independientes sino que pertenecen a grupos. lefty toppertenecen juntos como una Positionestructura, lengthy heightcomo Sizeestructura red, bluey greencomo Colorestructura. ¿Y tal vez la Colortransparencia pertenece a una Brushestructura? ¿Quizás Positiony Sizepertenece a una Rectangleestructura, en cuyo caso podemos considerar convertirlo en un Paintmétodo en el Rectangleobjeto? Entonces podemos terminar con:

Rectangle.Paint(brush);

¡Misión cumplida! Pero lo importante es que en realidad hemos mejorado el diseño general, y la reducción en el número de parámetros es una consecuencia de esto. Si solo reducimos el número de parámetros sin abordar los problemas subyacentes, podríamos hacer algo como esto:

Graphics.left = something;
Graphics.top = something;
Graphics.length = something;
...etc
Graphics.PaintRectangle();

Aquí hemos logrado la misma reducción en el número de parámetros, pero en realidad hemos empeorado el diseño .

En pocas palabras: para cualquier consejo de programación y reglas generales es muy importante comprender el razonamiento subyacente.

JacquesB
fuente
44
+1 respuesta agradable, constructiva, comprensible y no teórica.
AnoE
1
Sin mencionar, qué demonios está haciendo tu "cuadrado" teniendo tanto un atributo de longitud como de altura. :)
Comodín
1
+1 por reconocer que la tercera forma obvia implicada por algunas respuestas (es decir, muchas asignaciones a alguna estructura / objeto antes de la llamada a la función) no es mejor.
benxyzzy
@Wildcard: ¡Gracias, lo cambié a "rectángulo" para evitar confundir el problema!
JacquesB
7

¿Vale la pena usar variables globales para reducir el número de parámetros de las funciones o no?

No

Leí los primeros capítulos de este libro

¿Leíste el resto del libro?

Un global es solo un parámetro oculto. Causan un dolor diferente. Pero sigue siendo dolor. Deja de pensar en formas de evitar esta regla. Piensa en cómo seguirlo.

¿Qué es un parámetro?

Son cosas En una caja bien etiquetada. ¿Por qué importa cuántas cajas tienes cuando puedes poner cualquier cosa dentro?

Es el costo de envío y manejo.

Move(1, 2, 3, 4)

Dime que puedes leer eso. Adelante, inténtalo.

Move(PointA, PointB)

Es por eso.

Ese truco se llama introducir parámetro objeto .

Y sí, es solo un truco si todo lo que estás haciendo es contar parámetros. ¡Lo que debes contar es IDEAS! Abstracciones! ¿En qué me estás haciendo pensar a la vez? Mantenlo simple.

Ahora este es el mismo recuento:

Move(xyx, y)

¡AY! ¡Esto es horrible! ¿Qué salió mal aquí?

No es suficiente limitar el número de ideas. Deben ser ideas claras. ¿Qué diablos es un xyx?

Ahora esto todavía es débil. ¿Cuál es una forma más poderosa de pensar en esto?

Las funciones deben ser pequeñas. No más pequeño que eso.

Tío Bob

Move(PointB)

¿Por qué hacer que la función haga más de lo que realmente necesita hacer? El principio de responsabilidad única no es solo para las clases. En serio, vale la pena cambiar una arquitectura completa solo para evitar que una función se convierta en una pesadilla sobrecargada con 10 parámetros a veces relacionados, algunos de los cuales no se pueden usar con otros.

He visto código donde el número más común de líneas en una función era 1. En serio. No digo que tenga que escribir de esa manera, pero sí, no me diga que una global es la ÚNICA forma en que puede cumplir con esta regla. Deja de intentar salir de la refactorización de esa función correctamente. Sabes que puedes. Puede dividirse en algunas funciones. En realidad, podría convertirse en unos pocos objetos. Demonios, incluso podrías dividir parte de él en una aplicación completamente diferente.

El libro no te dice que cuentes tus parámetros. Te está diciendo que prestes atención al dolor que estás causando. Cualquier cosa que solucione el dolor soluciona el problema. Solo tenga en cuenta cuando simplemente está intercambiando un dolor por otro.

naranja confitada
fuente
3
"¿Leíste el resto del libro?" Su pregunta se responde en las primeras 8 palabras de mi publicación ...
OiciTrap
Estoy completamente de acuerdo: el punto es descomponer el problema en pedazos pequeños. Los objetos realmente pueden ayudar a organizar estas piezas y agruparlas, también permiten pasar una sola unidad conceptual como parámetro en lugar de un montón de piezas no conectadas. Me pongo ansioso cuando veo un método con más de 3 parámetros. 5 es una indicación de que mi diseño se ha estropeado y necesito otra ronda de refactorización. La mejor manera que he encontrado para resolver problemas de diseño como el conteo de parámetros es simplemente refactorizar las cosas en unidades más pequeñas y simples (clases / métodos).
Bill K
2
El tono de esta respuesta podría mejorarse. Se lee como muy abrupto y duro. Por ejemplo: "Dime que puedes leer eso. Continúa, prueba". parece muy agresivo y podría reescribirse como "De las dos llamadas de función arriba / abajo, ¿cuál es más fácil de leer?" Debes tratar de transmitir el punto sin la agresión. El OP solo está tratando de aprender.
Kyle A
No olvide que el OP también está tratando de mantenerse despierto.
candied_orange
4

Nunca usaría variables globales para reducir los parámetros. La razón es que cualquier función / comando puede alterar las variables globales, por lo que la entrada de la función no es confiable y propensa a valores que están fuera del alcance de lo que la función puede manejar. ¿Qué pasa si la variable se cambió durante la ejecución de la función y la mitad de la función tenía valores diferentes que la otra mitad?

Pasar parámetros, por otro lado, restringe el alcance de la variable a solo su propia función, de modo que solo la función puede modificar un parámetro una vez que se llama.

Si necesita pasar variables globales en lugar de un parámetro, es preferible rediseñar el código.

Solo mis dos centavos.

Dimos
fuente
"Nunca usaría variables globales para reducir los parámetros" totalmente de acuerdo. Crea un acoplamiento innecesario.
bytedev
2

Estoy con el tío Bob en esto y estoy de acuerdo en que más de 3 params es algo que se debe evitar (muy rara vez uso más de 3 params en una función). Tener muchos parámetros en una sola función crea un mayor problema de mantenimiento y probablemente sea un olor que su función está haciendo demasiado / tiene demasiadas responsabilidades.

Si está utilizando más de 3 en un método en un lenguaje OO, entonces debe considerar si los parámetros no están relacionados entre sí de alguna manera y, por lo tanto, ¿debería realmente pasar un objeto?

Además, si crea más funciones (más pequeñas), también notará que las funciones tienden a tener 3 parámetros o menos. La función / método de extracción es tu amigo :-).

¡No use variables globales como una forma de obtener más parámetros! ¡Eso está cambiando una mala práctica por una aún peor!

bytedev
fuente
1

Una alternativa válida a muchos parámetros de función es introducir un objeto de parámetro . Esto es útil si tiene un método compuesto que pasa (casi) todos sus parámetros a un montón de otros métodos.

En casos simples, este es un DTO simple que no tiene más que los parámetros antiguos como propiedades.

Timothy Truckle
fuente
1

Usar variables globales siempre parece una manera fácil de codificar (especialmente en un programa pequeño), pero hará que su código sea difícil de extender.

Sí, puede reducir el número de parámetros en una función utilizando una matriz para vincular los parámetros en una entidad.

function <functionname>(var1,var2,var3,var4.....var(n)){}

La función anterior se editará y cambiará a [usando una matriz asociativa] -

data=array(var1->var1,
           var2->var2
           var3->var3..
           .....
           ); // data is an associative array

function <functionname>(data)

Estoy de acuerdo con la respuesta de robert bristow-johnson : incluso puedes usar una estructura para vincular datos en una sola entidad.

Narender Parmar
fuente
1

Tomando un ejemplo de PHP 4, mira la firma de la función para mktime():

  • int mktime ([ int $hour = date("H") [, int $minute = date("i") [, int $second = date("s") [, int $month = date("n") [, int $day = date("j") [, int $year = date("Y") [, int $is_dst = -1 ]]]]]]] )

¿No te parece confuso? La función se llama "hacer tiempo", pero toma parámetros de día, mes y año, así como tres parámetros de tiempo. ¿Qué tan fácil es recordar en qué orden van? ¿Qué pasa si ves mktime(1, 2, 3, 4, 5, 2246);? ¿Puedes entender eso sin tener que referirte a nada más? ¿Se 2246interpreta como un tiempo de 24 horas "22:46"? ¿Qué significan los otros parámetros? Sería mejor como un objeto.

Pasando a PHP 5, ahora hay un objeto DateTime. Entre sus métodos hay dos llamados setDate()y setTime(). Sus firmas son las siguientes:

  • public DateTime setDate ( int $year , int $month , int $day )
  • public DateTime setTime ( int $hour , int $minute [, int $second = 0 ] )

Aún debe recordar que el orden de los parámetros va de mayor a menor, pero es una gran mejora. Tenga en cuenta que no hay un único método que le permita establecer los seis parámetros a la vez. Tienes que hacer dos llamadas separadas para hacer esto.

De lo que habla el tío Bob es de evitar tener una estructura plana. Los parámetros relacionados deben agruparse en un objeto, y si tiene más de tres parámetros, es muy probable que tenga un pseudo objeto allí, lo que le brinda la oportunidad de crear un objeto apropiado para una mayor separación. Aunque PHP no tiene una clase Datey una Timeclase separadas , podría considerar que DateTimerealmente contiene un Dateobjeto y un Timeobjeto.

Posiblemente podría tener la siguiente estructura:

<?php
$my_date = new Date;
$my_date->setDay(5);
$my_date->setMonth(4);
$my_date->setYear(2246);

$my_time = new Time;
$my_time->setHour(1);
$my_time->setMinute(2);
$my_time->setSecond(3);

$my_date_time = new DateTime;
$my_date_time->setTime($my_time);
$my_date_time->setDate($my_date);
?>

¿Es obligatorio establecer dos o tres parámetros cada vez? Si desea cambiar solo la hora o solo el día, ahora es fácil hacerlo. Sí, el objeto necesita ser validado para asegurarse de que cada parámetro funcione con los demás, pero ese fue el caso antes de todos modos.

Lo más importante es, ¿es más fácil de entender y, por lo tanto, mantener? El bloque de código en la parte inferior es más grande que una sola mktime()función, pero diría que es mucho más fácil de entender; incluso un no programador no tendría muchos problemas para resolver lo que hace. El objetivo no siempre es un código más corto o un código más inteligente, sino un código más fácil de mantener.

¡Ah, y no uses globals!

CJ Dennis
fuente
1

Muchas buenas respuestas aquí, sin embargo, la mayoría no aborda el punto. ¿Por qué estas reglas generales? Se trata de alcance, se trata de dependencias y se trata de un modelado adecuado.

Los argumentos globales para los argumentos son peores porque solo parece que lo hiciste más simple, pero de hecho solo escondiste la complejidad. Ya no lo ves en el prototipo, pero aún debes ser consciente de ello (lo cual es difícil ya que ya no puedes verlo) y entender la lógica de la función no te ayudará porque puede haber ser otra lógica oculta que interfiere a tus espaldas. Su alcance fue por todos lados e introdujo una dependencia de lo que sea porque lo que sea ahora puede alterar su variable. No está bien.

Lo principal que debe mantenerse para una función es que puede comprender lo que hace al mirar el prototipo y llamar. Entonces el nombre debe ser claro e inequívoco. Pero también, cuantos más argumentos haya, más difícil será comprender lo que hace. Amplía el alcance en su cabeza, hay demasiadas cosas sucediendo, es por eso que desea limitar el número. Sin embargo, es importante qué tipo de argumentos estás tratando, algunos son peores que otros. Un booleano opcional adicional que permite el procesamiento sin distinción entre mayúsculas y minúsculas no hace que la función sea más difícil de entender, por lo que no querrá hacer un gran problema al respecto. Como nota al margen, las enumeraciones hacen mejores argumentos que los booleanos porque el significado de una enumeración es obvio en la llamada.

El problema típico no es que escriba una nueva función con una enorme cantidad de argumentos, comenzará con solo unos pocos cuando aún no se dé cuenta de cuán complejo es realmente el problema que está resolviendo. A medida que su programa evoluciona, las listas de argumentos tienden a alargarse gradualmente. Una vez que un modelo se ha acordado, desea conservarlo porque es una referencia segura que conoce. Pero en retrospectiva, el modelo puede no ser tan bueno. Perdiste un paso o también en la lógica y no reconociste una entidad o dos. "Está bien ... podría comenzar de nuevo y pasar uno o dos días refactorizando mi código o ... podría agregar este argumento para poder hacer lo correcto después de todo y terminar con esto. Por ahora. Para este escenario "Para quitar este error de mi plato y poder mover la nota adhesiva a".

Cuanto más seguido elija la segunda solución, más costoso será el mantenimiento adicional y más difícil y poco atractivo será un refactorizador.

No existe una solución de placa de caldera para reducir el número de argumentos en una función existente. Agruparlos en compuestos no facilita realmente las cosas, es solo otra forma de eliminar la complejidad debajo de la alfombra. Hacerlo bien implica mirar de nuevo toda la pila de llamadas y reconocer lo que falta o se ha hecho mal.

Martin Maat
fuente
0

Varias veces descubrí que agrupar muchos parámetros que se enviaron juntos mejoró las cosas.

  • Te obliga a dar un buen nombre a esta agrupación de conceptos que se usan juntos. Si usa esos parámetros juntos, podría ser que tengan una relación (o que no debería usarlos en absoluto).

  • Una vez con el objeto, generalmente encuentro que se puede mover cierta funcionalidad que este objeto aparentemente estípido. Por lo general, es fácil de probar y con una gran cohesión y un bajo acoplamiento, lo que lo hace aún mejor.

  • La próxima vez que necesite agregar un nuevo parámetro, tengo un buen lugar para incluirlo sin cambiar la firma de muchos métodos.

Por lo tanto, puede que no funcione el 100% de las veces, pero pregúntese si esta lista de parámetros debe agruparse en un objeto. Y por favor. No use clases sin tipo como Tuple para evitar crear el objeto. Está utilizando programación orientada a objetos, no le importa crear más objetos si los necesita.

Borjab
fuente
0

Con el debido respeto, estoy bastante seguro de que se ha perdido completamente el punto de tener una pequeña cantidad de parámetros en una función.

La idea es que el cerebro solo puede contener tanta "información activa" a la vez, y si tiene n parámetros en una función, tiene n más piezas de "información activa" que deben estar en su cerebro para que sea fácil y precisa Comprenda lo que está haciendo el fragmento de código (Steve McConnell, en Code Complete (un libro mucho mejor, IMO), dice algo similar sobre 7 variables en el cuerpo de un método: rara vez alcanzamos eso, pero más y estás perdiendo el habilidad para mantener todo recto en tu cabeza).

El objetivo de un bajo número de variables es poder mantener pequeños los requisitos cognitivos de trabajar con este código, para que pueda trabajar en él (o leerlo) de manera más efectiva. Una causa secundaria de esto es que el código bien factorizado tenderá a tener cada vez menos parámetros (por ejemplo, un código mal factorizado tiende a agrupar un montón de cosas en un desastre).

Al pasar objetos en lugar de valores, quizás obtenga un nivel de abstracción para su cerebro porque ahora necesita darse cuenta de que sí, tengo un SearchContext para trabajar aquí en lugar de pensar en las 15 propiedades que podrían estar dentro de ese contexto de búsqueda.

Al intentar usar variables globales, has ido completamente en la dirección equivocada. Ahora no solo no ha resuelto los problemas de tener demasiados parámetros para una función, ¡ha tomado ese problema y lo ha arrojado a un problema mucho, mucho mejor que ahora tiene que tener en mente!

Ahora, en lugar de trabajar solo en el nivel de función, también debe considerar el alcance global de su proyecto (¡Dios mío, qué terrible! Me estremezco ...). Ni siquiera tiene toda su información frente a usted en la función (mierda, ¿cuál es ese nombre de variable global?) (Espero que esto no haya cambiado por algo más desde que llamé a esta función).

Las variables de alcance global son una de las peores cosas que se ven en un proyecto (grande o pequeño). Denotan una discapacidad para la gestión adecuada del alcance, que es una habilidad muy fundamental para la programación. Ellos. Son. Mal.

Al mover los parámetros fuera de su función y ponerlos en globales, se ha disparado en el suelo (o la pierna o la cara). Y Dios no quiera que decidas que , hey, puedo reutilizar este global para otra cosa ... mi mente tiembla ante el pensamiento.

Todo el ideal es mantener las cosas fáciles de administrar, y las variables globales NO lo harán. Llegaría al extremo de decir que son una de las peores cosas que puedes hacer para ir en la dirección opuesta.

jleach
fuente
-1

He encontrado un enfoque altamente efectivo (en JavaScript) para minimizar la fricción entre las interfaces: use una interfaz uniforme para todos los módulos , específicamente: funciones de parámetro único.

Cuando necesite múltiples parámetros: use un solo objeto / hash o matriz.

Ten paciencia, te prometo que no voy a trollear ...

Antes de decir "¿de qué sirve una función de parámetro único?" O "¿Hay alguna diferencia entre 1 matriz y funciones de múltiples argumentos?"

Bueno, sí. Quizás es visualmente sutil, pero la diferencia es múltiple: exploro los muchos beneficios aquí

Aparentemente, algunas personas piensan que 3 es el número correcto de argumentos. Algunos piensan que es 2. Bueno, eso todavía plantea la pregunta, "¿qué parámetro va en arg [0]?" En lugar de elegir la opción que restringe la interfaz con una declaración más rígida.

Creo que defiendo una posición más radical: no confíe en argumentos posicionales. Simplemente siento que es frágil y conduce a discusiones sobre la posición de los malditos argumentos. Sáltelo y avance a la inevitable lucha por los nombres de funciones y variables. 😉

Sin embargo, en serio, después de nombrar los ajustes, con suerte terminará con el siguiente código, que es algo autodocumentado, no sensible a la posición, y permite que los futuros cambios de parámetros se manejen dentro de la función:

function sendMessage({toUser, fromUser, subject, body}) { }

// And call the method like so:
sendMessage({toUser: this.parentUser, fromUser: this.currentUser, subject: ‘Example Alert’})

Dan Levy
fuente
66
Fingir argumentos con nombre no es realmente pasar un solo argumento.
JDługosz
¿Por qué es "falso" si logré una meta que me propuse? Estoy dando una mayor prioridad a los argumentos con nombre. Debido a que los argumentos posicionales no son obvios para llamar al código, y con el número de funciones nombradas que un desarrollador debe memorizar, no es útil recordar qué parámetros son dónde y cuáles opcionales. ... Eventualmente querrás agregar un parámetro requerido después de las opciones, buena suerte documentando y actualizando ese castillo de naipes.
Dan Levy
2
Los parámetros nombrados también son un truco de aprendizaje de refuerzo: los humanos otorgan más significado a las colecciones de palabras.
Dan Levy