¿Son malas las variables de bandera? ¿Son las siguientes clases de variables profundamente inmorales y es malo usarlas?
"variables booleanas o enteras a las que asigna un valor en ciertos lugares, luego, debajo, marca más adelante para hacer algo o no, como, por ejemplo, usar
newItem = true
algunas líneas a continuaciónif (newItem ) then
"
Recuerdo haber hecho un par de proyectos en los que descuidé totalmente el uso de banderas y terminé con una mejor arquitectura / código; sin embargo, es una práctica común en otros proyectos en los que trabajo, y cuando el código crece y se agregan banderas, también crece el espagueti en código de la OMI.
¿Diría que hay casos en los que usar banderas es una buena práctica o incluso necesario ?, o estaría de acuerdo en que usar banderas en el código son ... banderas rojas y deben evitarse / refactorizarse; yo, acabo de hacer funciones / métodos que verifican los estados en tiempo real.
fuente
newItem = true
algunas líneas a continuaciónif (newItem ) then
Respuestas:
El problema que he visto al mantener el código que hace uso de banderas es que el número de estados crece rápidamente, y casi siempre hay estados no controlados. Un ejemplo de mi propia experiencia: estaba trabajando en un código que tenía estos tres indicadores
Estos tres crearon ocho estados (en realidad, había otras dos banderas también). No todas las combinaciones de valores posibles estaban cubiertas por el código, y los usuarios estaban viendo errores:
Resultó que había situaciones en las que la suposición en la declaración if anterior era falsa.
Las banderas tienden a agravarse con el tiempo y ocultan el estado real de una clase. Por eso deben evitarse.
fuente
Aquí hay un ejemplo cuando las banderas son útiles.
Tengo un código que genera contraseñas (usando un generador de números pseudoaleatorios criptográficamente seguro). La persona que llama del método elige si la contraseña debe contener letras mayúsculas, minúsculas, dígitos, símbolos básicos, símbolos extendidos, símbolos griegos, cirílicos y unicode.
Con banderas, llamar a este método es fácil:
e incluso se puede simplificar para:
Sin banderas, ¿cuál sería la firma del método?
llamado así:
Como se señaló en los comentarios, otro enfoque sería utilizar una colección:
Esto es mucho más legible en comparación con el conjunto de
true
yfalse
, pero aún tiene dos inconvenientes:El principal inconveniente es que para permitir valores combinados, como
CharacterSet.LettersAndDigits
si estuviera escribiendo algo así en elGenerate()
método:posiblemente reescrito así:
Compare esto con lo que tiene usando banderas:
El segundo inconveniente menor es que no está claro cómo se comportaría el método si se llama así:
fuente
newItem = true
algunas líneas a continuaciónif (newItem ) then
Un gran bloque funcional es el olor, no las banderas. Si configura la bandera en la línea 5, solo verifique la bandera en la línea 354, entonces eso es malo. Si configura la bandera en la línea 8 y busca la bandera en la línea 10, está bien. Además, uno o dos indicadores por bloque de código están bien, 300 indicadores en una función son incorrectos.
fuente
Por lo general, las banderas se pueden reemplazar completamente por algún tipo de patrón de estrategia, con una implementación de estrategia para cada valor posible de la bandera. Esto hace que agregar un nuevo comportamiento sea mucho más fácil.
En situaciones críticas de rendimiento, el costo de la indirección puede aparecer y hacer que la deconstrucción se convierta en indicadores claros necesarios. Dicho esto, estoy teniendo problemas para recordar un solo caso en el que realmente tuve que hacer eso.
fuente
No, las banderas no son malas o un mal que debe ser refactorizado a toda costa.
Considere la llamada Pattern.compile (String regex, int flags) de Java . Esta es una máscara de bits tradicional y funciona. Eche un vistazo a las constantes en Java y cada vez que vea un grupo de 2 n , sabe que hay banderas allí.
En un mundo refactorizado ideal, se usaría un EnumSet donde las constantes son valores en una enumeración y como dice la documentación:
En un mundo perfecto, esa llamada Pattern.compile se convierte
Pattern.compile(String regex, EnumSet<PatternFlagEnum> flags)
.Todo lo dicho, sigue siendo banderas. Es mucho más fácil trabajar con
Pattern.compile("foo", Pattern.CASE_INSENSTIVE | Pattern.MULTILINE)
lo que sería tenerPattern.compile("foo", new PatternFlags().caseInsenstive().multiline())
u otro estilo de tratar de hacer lo que las banderas son realmente y para qué sirven.Las banderas se ven a menudo cuando se trabaja con elementos de nivel de sistema. Al interactuar con algo en el nivel del sistema operativo, es probable que tenga un indicador en alguna parte, ya sea el valor de retorno de un proceso, o los permisos de un archivo, o los indicadores para abrir un socket. Intentar refactorizar estas instancias en una cacería de brujas contra un olor de código percibido probablemente terminará con un código peor que si uno usara y entendiera la bandera.
El problema se produce cuando la gente usa mal las banderas que las unen y crean un conjunto de banderas francas de todo tipo de banderas no relacionadas o cuando intentan usarlas donde no son banderas.
fuente
Supongo que estamos hablando de banderas dentro de las firmas de métodos.
Usar una sola bandera ya es bastante malo.
No significará nada para sus colegas la primera vez que lo vean. Tendrán que mirar el código fuente del método para establecer lo que hace. Probablemente estarás en la misma posición unos meses después, cuando olvides de qué se trataba tu método.
Pasar una bandera al método, normalmente significa que su método es responsable de varias cosas. Dentro del método, probablemente esté haciendo una simple verificación en las líneas de:
Esa es una mala separación de preocupaciones y normalmente puedes encontrar una forma de evitarla.
Normalmente tengo dos métodos separados:
Esto tendrá más sentido con los nombres de métodos que son aplicables al problema que está resolviendo.
Pasar varias banderas es el doble de malo. Si realmente necesita pasar varios indicadores, entonces considere encapsularlos dentro de una clase. Incluso entonces, aún enfrentará el mismo problema, ya que su método probablemente esté haciendo varias cosas.
fuente
Las banderas y la mayoría de las variables temporales son un olor fuerte. Lo más probable es que puedan ser refactorizados y reemplazados con métodos de consulta.
Revisado:
Las banderas y las variables temporales al expresar el estado deben refactorizarse a los métodos de consulta. Los valores de estado (booleanos, ints y otras primitivas) casi siempre deben ocultarse como parte de los detalles de implementación.
Las banderas que se usan para el control, el enrutamiento y el flujo general del programa también pueden indicar la oportunidad de refactorizar secciones de las estructuras de control en estrategias o fábricas separadas, o lo que sea apropiado según la situación, que continúe utilizando los métodos de consulta.
fuente
Cuando hablamos de indicadores, debemos saber que se modificarán con el tiempo de ejecución del programa y que afectarán el comportamiento del programa en función de sus estados. Mientras tengamos un control claro sobre estas dos cosas, funcionarán muy bien.
Las banderas pueden funcionar muy bien si
Si hay muchas banderas, un buen trabajo de diseño debe preceder, ya que las banderas comienzan a jugar un papel clave en el comportamiento del programa. Puede ir a los diagramas de estado para modelar. Dichos diagramas también funcionan como documentación y orientación visual al tratar con ellos.
Mientras estas cosas estén en su lugar, creo que no conducirá al desastre.
fuente
Supuse por la pregunta que el QA significaba variables de marca (globales), y no bits de un parámetro de función.
Hay situaciones en las que no tienes muchas otras posibilidades. Por ejemplo, sin un sistema operativo, debe evaluar las interrupciones. Si se produce una interrupción con mucha frecuencia y no tiene tiempo para realizar una evaluación prolongada en el ISR, no solo está permitido, sino que a veces, incluso las mejores prácticas solo establecen algunos indicadores globales en el ISR (debe pasar el menor tiempo posible) en el ISR), y para evaluar esas banderas en su bucle principal.
fuente
No creo que nada sea un mal absoluto en la programación, nunca.
Hay otra situación en la que las banderas podrían estar en orden, que aún no se mencionaron aquí ...
Considere el uso de cierres en este fragmento de Javascript:
La función interna, que se pasa a "Array.forEach", no puede simplemente "devolver verdadero".
Por lo tanto, debe mantener el estado afuera con una bandera.
fuente