¿Es una buena práctica definir una variable para nombrar un argumento de método?

73

En aras de la legibilidad, a menudo me encuentro definiendo variables temporales mientras invoco funciones, como el siguiente código

var preventUndo = true;
doSomething(preventUndo);

La versión más corta de esto a esto sería,

doSomething(true);

Pero cuando vuelvo al código, a menudo me pregunto a qué se truerefiere. ¿Existe una convención para este tipo de acertijo?

Duopixel
fuente
55
¿Usas algún tipo de IDE? La mayoría tendrá algún tipo de forma de indicar cuáles son los parámetros de la función que está llamando, lo que anula un poco la necesidad de hacer esto.
Matthew Scharley el
44
No uso un IDE, pero incluso entonces supongo que la sugerencia requerirá algún tipo de acción (pasar el mouse o moverse a la línea). Me gusta saber qué está haciendo mi código con solo mirarlo.
methodofaction
11
Si el idioma lo admite, podría usar una enumeración comodoSomething( Undo.PREVENT )
James P.
44
Pero puedes definir Undo = { PREVENT = true, DONT_PREVENT = false }. Pero en JavaScript, la convención es hacerlo así: function myFunction( mandatoryArg1, mandatoryArg2, otherArgs ) { /*...*/ }y luego myFunction( 1, 2, { option1: true, option2: false } ).
xavierm02
66
Definitivamente depende del idioma. Si esto fuera python, por ejemplo, sugeriría simplemente usar argumentos de palabras clave, por ejemplodoSomething(preventUndo=True)
Joel Cornett el

Respuestas:

117

Explicando las variables

Su caso es un ejemplo de la introducción que explica la refactorización variable . En resumen, una variable explicativa es una que no es estrictamente necesaria, pero le permite dar un nombre claro a algo, con el objetivo de aumentar la legibilidad.

El código de buena calidad comunica la intención al lector; y como desarrollador profesional, la legibilidad y la mantenibilidad son sus objetivos número 1.

Como tal, la regla general que recomendaría es esta: si el propósito de su parámetro no es inmediatamente obvio, no dude en usar una variable para darle un buen nombre. Creo que esta es una buena práctica en general (a menos que se abuse de ella). Aquí hay un ejemplo rápido y artificial: considere:

editButton.Enabled = (_grid.SelectedRow != null && ((Person)_grid.SelectedRow).Status == PersonStatus.Active);

versus el un poco más largo, pero posiblemente más claro:

bool personIsSelected = (_grid.SelectedRow != null);
bool selectedPersonIsEditable = (personIsSelected && ((Person)_grid.SelectedRow).Status == PersonStatus.Active)
editButton.Enabled = (personIsSelected && selectedPersonIsEditable);

Parámetros booleanos

Su ejemplo realmente resalta por qué los booleanos en las API a menudo son una mala idea : por el lado de la llamada, no hacen nada para explicar lo que está sucediendo. Considerar:

ParseFolder(true, false);

Tendría que buscar qué significan esos parámetros; si fueran enumeraciones, sería mucho más claro:

ParseFolder(ParseBehaviour.Recursive, CompatibilityOption.Strict);

Editar:

Se agregaron encabezados e intercambiaron el orden de los dos párrafos principales, porque mucha gente se estaba enfocando en la parte de los parámetros booleanos (para ser justos, originalmente era el primer párrafo). También se agregó un ejemplo a la primera parte.

Daniel B
fuente
28
A menos que use parámetros con nombre (argumentos con nombre en .NET Framework), en cuyo caso doSomething(preventUndo: true);es lo suficientemente claro. Además, ¿crear una enumeración para cada booleano en su API? ¿Seriamente?
Arseni Mourzenko
12
@MainMa: Si el lenguaje que está usando no es lo suficientemente bueno como para admitir argumentos con nombre, usar una enumeración es una buena opción. Esto no significa que deba introducir sistemáticamente enumeraciones en todas partes.
Giorgio el
18
@MainMa: para responder a esa pregunta, el punto realmente es que no debería tener booleanos en sus API (al menos, sus públicas). Debería cambiar a una sintaxis de argumento con nombre, que posiblemente no sea idiomática (en el momento de la escritura), y en cualquier caso, un parámetro booleano casi siempre significa que su método hace dos cosas, y está permitiendo que la persona que llama escoger. Pero el punto de mi respuesta fue que no hay nada de malo en usar variables explicativas en su código; En realidad es una muy buena práctica.
Daniel B el
3
Es una parte permanente del lenguaje C #, ¿qué más "aceptación convencional" necesita? Incluso para alguien que aún no conoce la construcción (lo que significa que sus desarrolladores de C # ni siquiera han leído los documentos de C #), es bastante obvio lo que hace.
Nate CK
3
Es por eso que MS publica esos agradables resúmenes de todas las cosas nuevas que han agregado en cada versión, no creo que genere mucho trabajo leer uno de estos cada dos años: msdn.microsoft.com/en- us / library / bb383815% 28v = vs.100% 29.aspx
Nate CK
43

No escriba código que no necesita.

Si le resulta doSomething(true)difícil de entender, debe agregar un comentario:

// Do something and prevent the undo.
doSomething(true);

o, si el idioma lo admite, agregue el nombre del parámetro:

doSomething(preventUndo: true);

De lo contrario, confíe en su IDE para obtener la firma del método llamado:

ingrese la descripción de la imagen aquí

Casos donde es útil

Poner una variable adicional puede ser útil:

  1. Para fines de depuración:

    var productId = this.Data.GetLastProductId();
    this.Data.AddToCart(productId);
    

    Se puede escribir el mismo código en una sola línea, pero si desea poner un punto de interrupción antes de agregar un producto al carrito para ver si la identificación del producto es correcta, escribir dos líneas en lugar de una es una buena idea.

  2. Si tiene un método con muchos parámetros y cada parámetro parte de una evaluación. En una línea, esto puede volverse totalmente ilegible.

    // Even with indentation, this is unreadable.
    var doSomething(
        isSomethingElse ? 0 : this.getAValue(),
        this.getAnotherOne() ?? this.default,
        (a + b + c + d + e) * f,
        this.hello ? this.world : (this.hello2 ? this.world2 : -1));
    
  3. Si la evaluación de un parámetro es demasiado complicada. Un ejemplo de un código que he visto:

    // Wouldn't it be easier to have several if/else's (maybe even in a separate method)?
    do(something ? (hello ? world : -1) : (programmers ? stackexchange : (com ? -1 : 0)));
    

¿Por qué no en otros casos?

¿Por qué no deberías crear variables adicionales en casos simples?

  1. No por el impacto en el rendimiento. Esta sería una suposición muy errónea de un desarrollador principiante que está micro optimizando su aplicación. No hay impacto en el rendimiento en la mayoría de los idiomas, ya que el compilador incorporará la variable. En aquellos idiomas en los que el compilador no hace eso, puede ganar unos pocos microsegundos al incluirlo a mano, lo que no vale la pena. No hagas eso.

  2. Pero debido al riesgo de disociar el nombre que le da a la variable al nombre del parámetro.

    Ejemplo:

    Digamos que el código original es:

    void doSomething(bool preventUndo)
    {
        // Does something very interesting.
        undoHistory.removeLast();
    }
    
    // Later in code:
    var preventUndo = true;
    doSomething(preventUndo);
    

    Más tarde, un desarrollador que trabaja en doSomethingavisos de que recientemente, el historial de deshacer introdujo dos nuevos métodos:

    undoHistory.clearAll() { ... }
    undoHistory.disable() { ... }
    

    Ahora, preventUndoparece no muy claro. ¿Significa que solo se evitará la última acción? ¿O tal vez significa que el usuario ya no podrá usar la función de deshacer? ¿O que se borrará el historial de deshacer? Los nombres más claros serían:

    doSomething(bool hideLastUndo) { ... }
    doSomething(bool removeAllUndo) { ... }
    doSomething(bool disableUndoFeature) { ... }
    

    Entonces ahora tienes:

    void doSomething(bool hideLastUndo)
    {
        // Does something very interesting.
        undoHistory.removeLast();
    }
    
    // Later in code, very error prone, while the signature of the method is clear:
    var preventUndo = true;
    doSomething(preventUndo);
    

¿Qué hay de las enumeraciones?

Algunas otras personas sugirieron usar enumeraciones. Si bien resuelve el problema inmediato, crea uno más grande. Vamos a ver:

enum undoPrevention
{
    keepInHistory,
    prevent,
}

void doSomething(undoPrevention preventUndo)
{
    doTheJob();
    if (preventUndo == undoPrevention.prevent)
    {
        this.undoHistory.discardLastEntry();
    }
}

doSomething(undoPrevention.prevent);

Problemas con eso:

  1. Es demasiado código. if (preventUndo == undoPrevention.prevent)? ¡¿Seriamente?! No quiero escribir tal ifs cada vez.

  2. Agregar un elemento a la enumeración es muy tentador más adelante, si estoy usando la misma enumeración en otro lugar. ¿Qué pasa si lo modifico así:

    enum undoPrevention
    {
        keepInHistory,
        prevent,
        keepButDisable, // Keeps the entry in the history, but makes it disabled.
    }
    

    ¿Que pasará ahora? ¿El doSomethingmétodo funcionará como se espera? Para evitar esto, sería necesario escribir este método de esta manera desde el principio:

    void doSomething(undoPrevention preventUndo)
    {
        if (![undoPrevention.keepInHistory, undoPrevention.prevent].contains(preventUndo))
        {
            throw new ArgumentException('preventUndo');
        }
    
        doTheJob();
        if (preventUndo == undoPrevention.prevent)
        {
            this.undoHistory.discardLastEntry();
        }
    }
    

    ¡La variante que usa booleanos comienza a verse muy bien!

    void doSomething(bool preventUndo)
    {
        doTheJob();
        if (preventUndo)
        {
            this.undoHistory.discardLastEntry();
        }
    }
    
MainMa
fuente
3
"Es demasiado código. If (preventUndo == undoPrevention.prevent)? ¡¿En serio ?! No quiero escribir tales ifs cada vez". Además, si usa un booleano, necesita una declaración if de todos modos. Honestamente, tu crítica sobre este punto me parece un poco artificial.
Giorgio el
1
Me falta una solución alternativa aquí. ¿Estás diciendo que debería apegarse a lo que se dice, nada simple y verdadero y confiar en el IDE (que no usa)? Un comentario podría pudrirse como el nombre de la variable.
Seguro el
2
@superM: No me resulta mucho más difícil cambiar el nombre de una variable temporal utilizada solo para la llamada. Si se cambia un nombre de enumeración, entonces es aún mejor, porque el código de llamada ya no se ejecutará y arrojará un error directamente a su cara. Si la funcionalidad de la función cambia radicalmente por una extensión enum, entonces debe volver a visitar todas las llamadas para una mayor corrección, de todos modos, de lo contrario, programa con esperanza, no con lógica. Ni siquiera pensar en cambiar los valores, por ejemplo, negando preventUndoa allowUndola firma ...
Asegure
44
@superM mantener los comentarios sincronizados con el código es muy propenso a problemas, ya que no tiene ayuda de su compilador en su búsqueda de inconsistencias.
Buhb
77
"... confíe en su IDE para obtener la firma del método llamado"; esto es útil para cuando está escribiendo el código, pero no tanto cuando lo está leyendo. Cuando leo el código de una clase, quiero saber qué está haciendo con solo mirarlo. Si tiene que confiar en la IDE para facilitar la lectura, su código no se documenta automáticamente.
Phil
20

Tampoco deberías escribir métodos con banderas booleanas.

Para citar a Robert C. Martin, dice en su libro Clean Code (ISBN-13 978-0-13-235088-4), "Pasar un booleano a una función es una práctica verdaderamente terrible".

Para parafrasearlo, el razonamiento es que el hecho de que tenga un interruptor verdadero / falso significa que su método probablemente esté haciendo dos cosas diferentes (es decir, "Hacer algo con deshacer" y "Hacer algo sin deshacer"), y por lo tanto debe ser dividido en dos métodos diferentes (que internamente pueden llamar lo mismo).

DoSomething()
{...

DoSomethingUndoable()
{....
Nick B.
fuente
77
Según esa lógica, mi único constructor HotDog necesitaría tener unos 16 métodos diferentes: HotDogWithMustardRelishKrautOnion (), HotDogWithMustardNorelishKrautOnion (), etc. O podría ser un simple HotDogWithOptions (opciones int), en el que interpreto las opciones como un campo de bits, pero luego volvemos a un método que hace varias cosas supuestamente diferentes. Entonces, si voy con la primera opción, ¿tengo que escribir un gran condicional para ordenar a qué constructor llamar en función de las cosas que de otro modo habrían sido parámetros booleanos? Y si la Q usa un int, esta A no responde la Q.
Caleb
44
Después de leer todas las respuestas y mirar mi código, llego a la conclusión de que esta es la forma correcta de hacerlo. doSomethingUndoable()podría capturar los cambios y luego llamar adoSomething()
methodofaction
1
Entonces, si tengo una función que procesa mucho y tiene la opción de enviar un correo electrónico cuando se hace, no debería tener un argumento booleano que pueda evitar que se envíe el correo electrónico, ¿debería crear una función separada?
yakatz el
2
@Caleb En este caso, haría un hot dog y agregaría los ingredientes uno por uno, o en un lenguaje fuertemente tipado le pasaría un objeto HotDogSettings en el que habría configurado todas las banderas booleanas. No tendría 15 banderas de verdadero / falso diferentes que serían una pesadilla para mantener. recuerde que el código se trata de mantenimiento, no de escritura, ya que es donde está el 80% del costo de la aplicación. var hd = MakeHotDog (); hd.Add (Onion); ...
Nick B.
2
@Caleb Creo que la distinción es que su ejemplo usa los booleanos como un campo de datos real, mientras que la mayoría de los usos son para impulsar el flujo de ejecución; por lo tanto, el tío Bob está gritando contra ella. Además, su consejo es un poco extremo: las siguientes líneas del libro aconsejan no tener más de 2 parámetros, lo que posiblemente sea una postura aún más extrema. Sin embargo, hay un método para la locura. Sin embargo, tiene toda la razón en que no responde la pregunta, un error que cometí en mi propia respuesta.
Daniel B
5

Cuando observa dos clases para ver qué tan acopladas están, una de las categorías es el acoplamiento de datos , que se refiere al código en una clase llamando a los métodos de otra clase y simplemente pasando datos, como para qué mes desea un informe y otro La categoría es el acoplamiento de control , llamar a métodos y pasar algo que controla el comportamiento del método. El ejemplo que uso en clase es una verbosebandera o una reportTypebandera, pero preventUndotambién es un gran ejemplo. Como acaba de demostrar, el acoplamiento de control dificulta la lectura del código de llamada y la comprensión de lo que sucede. También hace que el código de llamada sea vulnerable a los cambios doSomething()que usan el mismo indicador para controlar tanto deshacer como archivar, o agregar otro parámetro adoSomething() para controlar el archivado, rompiendo así su código, etc.

El problema es que el código está muy bien acoplado. Pasar un bool para controlar el comportamiento es, en mi opinión, una señal de una mala API. Si posee la API, cámbiela. Dos métodos, doSomething()y doSomethingWithUndo(), sería mejor. si no lo posee, escriba dos métodos de envoltura usted mismo en el código que sí posee, y haga que uno de ellos llame doSomething(true)y el otro llame doSomething(false).

Kate Gregory
fuente
4

No es el rol del llamante definir el rol de los argumentos. Siempre busco la versión en línea y compruebo la firma de la función llamada si tengo dudas.

La variable debe nombrarse después de su rol en el alcance actual. No El alcance donde se envían.

Simon Bergot
fuente
1
El papel de la variable en el alcance actual es decir para qué se utiliza. No veo cómo esto contradice el uso de variables temporales por parte de OP.
SuperM
4

Lo que haría en JavaScript es que la función tome un objeto como el único parámetro similar a este:

function doSomething(settings) {
    var preventUndo = settings.hasOwnProperty('preventUndo') ? settings.preventUndo : false;
    // Deal with preventUndo in the normal way.
}

Luego llámalo con:

doSomething({preventUndo: true});
ridecar2
fuente
¡¡¡DECIR AH!!! ¡Ambos hicimos un doSomething(x)método! jaja ... Ni siquiera me di cuenta de tu publicación hasta ahora.
carne
¿Qué pasaría si pasara una cadena "noUndo", y cómo queda claro para la persona que usa su firma qué configuración se supone que debe contener sin analizar la implementación?
Nick B.
1
Documenta tu código. Eso es lo que todos los demás hacen. Facilita la lectura de su código, escribirlo solo tiene que suceder una vez.
ridecar2
1
@NickB. La convención es poderosa. Si la mayor parte de su código acepta objetos con argumentos, esto está claro.
orip
4

Soy aficionado a aprovechar las características del lenguaje para ayudarme a aclararme. Por ejemplo, en C # puede especificar parámetros por nombre:

 CallSomething(name: "So and so", age: 12, description: "A random person.");

En JavaScript, generalmente prefiero usar un objeto de opciones como argumento por este motivo:

function doSomething(args) { /*...*/ }

doSomething({ name: 'So and so', age: 12, description: 'A random person.' });

Sin embargo, esa es solo mi preferencia. Supongo que dependerá en gran medida del método que se llame y de cómo el IDE ayuda al desarrollador a comprender la firma.

carne
fuente
1
Esa es la "desventaja" de los idiomas mecanografiados libremente. Realmente no se puede aplicar una firma sin alguna validación. No sabía que podría agregar nombres como ese en JS.
James P.
1
@JamesPoulson: Probablemente sabías que podías hacer eso en JS y simplemente no te diste cuenta. Todo ha terminado en JQuery: $.ajax({url:'', data:''})etc., etc.
blesh
Cierto. Parece inusual a primera vista, pero es similar a los pseudo objetos en línea que pueden existir en algunos idiomas.
James P.
3

Creo que este es el más simple y fácil de leer:

enum Undo { ALLOW, PREVENT }

doSomething(Undo u) {
    if (Undo.ALLOW == u) {
        // save stuff to undo later.
    }
    // do your thing
}

doSomething(Undo.ALLOW);

A MainMa no le gusta eso. Es posible que tengamos que estar de acuerdo en no estar de acuerdo, o podemos usar una solución que Joshua Bloch propone:

enum Undo {
    ALLOW {
        @Override
        public void createUndoBuffer() {
            // put undo code here
        }
    },
    PREVENT {
        @Override
        public void createUndoBuffer() {
            // do nothing
        }
    };

    public abstract void createUndoBuffer();
}

doSomething(Undo u) {
    u.createUndoBuffer();
    // do your thing
}

Ahora, si alguna vez agrega un Undo.LIMITED_UNDO, su código no se compilará a menos que implemente el método createUndoBuffer (). Y en doSomething () no hay if (Undo.ALLOW == u). Lo hice en ambos sentidos y el segundo método es bastante pesado y un poco difícil de entender cuando la enumeración Deshacer se expande a páginas y páginas de código, pero te hace pensar. Por lo general, me quedo con el método más simple para reemplazar un booleano simple con una enumeración de 2 valores hasta que tenga razones para cambiar. Cuando agrego un tercer valor, utilizo mi IDE para "Buscar usos" y arreglar todo.

GlenPeterson
fuente
2

Creo que su solución hace que su código sea un poco más legible, pero evitaría definir una variable adicional solo para que su función llame más claramente. Además, si desea utilizar una variable adicional, la marcaría como constante si su lenguaje de programación lo admite.

Se me ocurren dos alternativas que no implican una variable adicional:

1. Use un comentario extra

doSomething(/* preventUndo */ true);

2. Use una enumeración de dos valores en lugar de boolean

enum Options
{
    PreventUndo,
    ...
}

...

doSomething(PreventUndo);

Puede usar la alternativa 2 si su idioma admite enumeraciones.

EDITAR

Por supuesto, usar argumentos con nombre también es una opción, si su idioma los admite.

En cuanto a la codificación adicional que necesitan las enumeraciones, realmente me parece insignificante. En lugar de

if (preventUndo)
{
    ...
}

tienes

if (undoOption == PreventUndo)
{
    ...
}

o

switch (undoOption)
{
  case PreventUndo:
  ...
}

E incluso si se trata de escribir un poco más, recuerde que el código se escribe una vez y se lee muchas veces, por lo que puede valer la pena escribir un poco más ahora para encontrar un código más legible seis meses después.

Giorgio
fuente
2

Estoy de acuerdo con lo que dijo @GlenPeterson:

doSomething(Undo.ALLOW); // call using a self evident enum

pero también interesante sería el siguiente, ya que me parece que solo hay dos posibilidades (verdadero o falso)

//Two methods    

doSomething()  // this method does something but doesn't prevent undo

doSomethingPreventUndo() // this method does something and prevents undo
Tulains Córdova
fuente
2
Buena idea, no había pensado en eso. Cuando te vuelves más complicado como doSomething (String, String, String, boolean, boolean, boolean), las constantes con nombre son la única solución razonable. Bueno, Josh Bloch sugiere un objeto de fábrica y constructor como en: MyThingMaker thingMaker = MyThingMaker.new (); thingMaker.setFirstString ("Hola"); thingMaker.setSecondString ("Allí"); etc ... Cosa t = thingMaker.makeIt (); t.doSomething (); Eso es mucho más trabajo, por lo que será mejor que valga la pena.
GlenPeterson el
Un problema con este último enfoque es que hace que sea incómodo escribir un método que use doSomethingpero que le permita a la persona que llama elegir si desea deshacer. Una solución puede ser tener una sobrecarga que tome la opción booleana, pero también tener versiones de envoltura que llamen a la versión anterior con el parámetro siempre verdadero o siempre falso.
supercat
@GlenPeterson Una fábrica es una posibilidad y es posible en Javascript (mencionado por OP).
James P.
2

Como está preguntando sobre JavaScript principalmente, al usar coffeescript puede tener un argumento con nombre como sintaxis, súper fácil:

# declare method, ={} declares a default value to prevent null reference errors
doSomething = ({preventUndo} = {}) ->
  if preventUndo
    undo = no
  else
    undo = yes

#call method
doSomething preventUndo: yes
#or 
doSomething(preventUndo: yes)

compila a

var doSomething;

doSomething = function(_arg) {
  var preventUndo, undo;
  preventUndo = (_arg != null ? _arg : {}).preventUndo;
  if (preventUndo) {
    return undo = false;
  } else {
    return undo = true;
  }
};

doSomething({
  preventUndo: true
});

doSomething({
  preventUndo: true
});

Diviértete en http://js2coffee.org/ para probar las posibilidades

Guillaume86
fuente
Utilizo coffeeScript solo cuando necesito evitar la locura OOP de javascript. Esta es una buena solución que podría usar cuando codifique solo, ¡sería difícil justificar a un compañero de trabajo que estoy pasando un objeto en lugar de un booleano en aras de la legibilidad!
methodofaction
1

Solo para una solución menos convencional y dado que el OP mencionó Javascript, una posibilidad es usar una matriz asociativa para asignar valores. La ventaja sobre un solo booleano es que puede tener tantos argumentos como desee y no preocuparse por su secuencia.

var doSomethingOptions = new Array();

doSomethingOptions["PREVENTUNDO"] = true;
doSomethingOptions["TESTMODE"] = false;

doSomething( doSomethingOptions );

// ...

function doSomething( doSomethingOptions ){
    // Check for null here
    if( doSomethingOptions["PREVENTUNDO"] ) // ...
}

Me doy cuenta de que esto es un reflejo de alguien de un fondo fuertemente tipado y puede que no sea tan práctico, pero considere esto por originalidad.

Otra posibilidad es tener un objeto y también es posible en Javascript. No estoy 100% seguro de que esto sea sintácticamente correcto. Eche un vistazo a patrones como Factory para obtener más inspiración.

function SomethingDoer( preventUndo ) {
    this.preventUndo = preventUndo;
    this.doSomething = function() {
            if( this.preventUndo ){
                    // ...
            }
    };
}

mySomethingDoer = new SomethingDoer(true).doSomething();
James Poulson
fuente
1
Creo que esto se puede escribir mejor en la notación de punto ( doSomethingOptions.PREVENTUNDO) en lugar de la notación de acceso a la matriz.
Paŭlo Ebermann
1

El enfoque de su pregunta y de las otras respuestas es mejorar la legibilidad donde se llama la función, que es un enfoque con el que estoy de acuerdo. Cualquier directriz específica, evento "sin argumentos booleanos", siempre debe funcionar como un medio para este fin y no convertirse y terminar ellos mismos.

Creo que es útil tener en cuenta que este problema se evita principalmente cuando el lenguaje de programación admite argumentos con nombre / argumentos de palabras clave, como en C # 4 y Python, o cuando los argumentos del método están intercalados en el nombre del método, como en Smalltalk o Objective-C.

Ejemplos:

// C# 4
foo.doSomething(preventUndo: true);
# Python
foo.doSomething(preventUndo=True)
// Objective-C
[foo doSomethingWith:bar shouldPreventUndo:YES];
orip
fuente
0

Se debe evitar pasar variables booleanas como argumentos a las funciones. Porque las funciones deberían hacer una cosa a la vez. Al pasar la variable booleana, la función tiene dos comportamientos. Esto también crea un problema de legibilidad para una etapa posterior o para otros programadores que tienden a ver su código. Esto también crea un problema al probar la función. Probablemente en este caso tienes que crear dos casos de prueba. Imagine que tiene una función que tiene una declaración de cambio y cambia su comportamiento en función del tipo de cambio, entonces debe tener tantos casos de prueba diferentes definidos para él.

Cada vez que uno tiene un argumento booleano para la función, tiene que modificar el código para que no escriba ningún argumento booleano.

Ganji
fuente
Entonces, ¿convertiría una función con un argumento booleano en dos funciones que solo difieren en una pequeña parte de su código (donde el original tendría un if(param) {...} else {...})?
Paŭlo Ebermann
-1
int preventUndo = true;
doSomething(preventUndo);

Un buen compilador para lenguajes de bajo nivel como C ++ optimizará el código de máquina de más de 2 líneas de la siguiente manera:

doSomething(true); 

por lo que no importa en el rendimiento, pero aumentará la legibilidad.

También es útil usar una variable en caso de que se convierta en variable más adelante y también pueda aceptar otros valores.

Akash Agrawal
fuente