¿Por qué el Estado global es tan malo?

304

Antes de comenzar esto, permítame decir que estoy bien al tanto de los conceptos de abstracción y inyección de dependencia. No necesito que mis ojos estén abiertos aquí.

Bueno, la mayoría de nosotros decimos, (también) muchas veces sin entender realmente, "No utilices variables globales" o "Los singletons son malos porque son globales". Pero, ¿qué es realmente tan malo sobre el estado global siniestro?

Supongamos que necesito una configuración global para mi aplicación, por ejemplo, las rutas de las carpetas del sistema o las credenciales de la base de datos de toda la aplicación.

En ese caso, no veo otra solución que no sea proporcionar estas configuraciones en algún tipo de espacio global, que estará disponible para toda la aplicación.

Sé que es malo abusar , pero ¿es realmente ESO el espacio global? Y si es así, ¿qué buenas alternativas hay?

    
pregunta Madara Uchiha 10.05.2012 - 21:35
fuente

17 respuestas

262

Muy brevemente, hace que el estado del programa sea impredecible.

Para elaborar, imagine que tiene un par de objetos que usan la misma variable global. Suponiendo que no está utilizando una fuente de aleatoriedad en cualquier lugar dentro de cualquiera de los módulos, entonces la salida de un método particular puede predecirse (y, por lo tanto, probarse) si se conoce el estado del sistema antes de ejecutar el método.

Sin embargo, si un método en uno de los objetos desencadena un efecto secundario que cambia el valor del estado global compartido, entonces ya no sabrá cuál es el estado de inicio cuando ejecuta un método en el otro objeto. Ahora ya no puede predecir qué salida obtendrá cuando ejecute el método y, por lo tanto, no puede probarlo.

En un nivel académico, esto puede no parecer tan serio, pero el hecho de poder unificar el código de prueba es un paso importante en el proceso de demostrar su corrección (o al menos la idoneidad para un propósito).

En el mundo real, esto puede tener algunas consecuencias muy serias. Supongamos que tiene una clase que llena una estructura de datos global y una clase diferente que consume los datos en esa estructura de datos, cambiando su estado o destruyéndolos en el proceso. Si la clase de procesador ejecuta un método antes de que se complete la clase de populador, el resultado es que la clase de procesador probablemente tendrá datos incompletos para procesar, y la estructura de datos en la que estaba trabajando la clase de populador podría corromperse o destruirse. El comportamiento del programa en estas circunstancias se vuelve completamente impredecible, y probablemente conducirá a una pérdida épica.

Además, el estado global daña la legibilidad de su código. Si su código tiene una dependencia externa que no se introduce explícitamente en el código, quienquiera que tenga la tarea de mantener su código tendrá que buscarlo para averiguar de dónde proviene.

En cuanto a qué alternativas existen, bueno, es imposible no tener ningún estado global, pero en la práctica, generalmente es posible restringir el estado global a un solo objeto que envuelve a todos los demás, y al que nunca se debe hacer referencia al confiar en Las reglas de alcance del lenguaje que estás usando. Si un objeto en particular necesita un estado en particular, entonces debe solicitarlo explícitamente al pasarlo como un argumento a su constructor o mediante un método de establecimiento. Esto se conoce como inyección de dependencia.

Puede parecer una tontería pasar en un estado al que ya se puede acceder debido a las reglas de alcance del idioma que esté usando, pero las ventajas son enormes. Ahora, si alguien mira el código de forma aislada, queda claro qué estado necesita y de dónde proviene. También tiene enormes beneficios en cuanto a la flexibilidad de su módulo de código y, por lo tanto, las oportunidades para reutilizarlo en diferentes contextos. Si se pasa el estado y los cambios al estado son locales al bloque de código, entonces puede pasar el estado que desee (si es el tipo de datos correcto) y hacer que el código lo procese. El código escrito en este estilo tiende a tener la apariencia de una colección de componentes asociados sueltos que pueden intercambiarse fácilmente. El código de un módulo no debería importar de dónde viene el estado, solo cómo procesarlo. Si pasa el estado a un bloque de código, ese bloque de código puede existir de forma aislada, no es así si confía en el estado global.

Hay muchas otras razones por las que pasar el estado es muy superior a depender del estado global. Esta respuesta no es de ninguna manera completa. Probablemente podrías escribir un libro completo sobre por qué el estado global es malo.

    
respondido por el GordonM 10.05.2012 - 21:37
fuente
123

El estado global mutable es malo por muchas razones:

  • Errores del estado global mutable : muchos errores son causados por la mutabilidad. Los errores que pueden ser causados por la mutación desde cualquier parte del programa son incluso más complejos, ya que a menudo es difícil rastrear la causa exacta
  • Mala capacidad de prueba : si tiene un estado global mutable, deberá configurarlo para cualquier prueba que escriba. Esto hace que las pruebas sean más difíciles (¡y las personas que son personas tienen menos probabilidades de hacerlo!). p.ej. en el caso de las credenciales de la base de datos de toda la aplicación, ¿qué sucede si una prueba necesita acceder a una base de datos de prueba específica diferente de todo lo demás?
  • Inflexibilidad : ¿qué sucede si una parte del código requiere un valor en el estado global, pero otra parte requiere otro valor (por ejemplo, un valor temporal durante una transacción)? De repente, tienes un poco de refactorización en tus manos
  • Impureza de la función : las funciones "puras" (es decir, aquellas en las que el resultado depende solo de los parámetros de entrada y no tienen efectos secundarios) son mucho más fáciles de razonar y componer para crear programas más grandes. Las funciones que leen o manipulan el estado global mutable son inherentemente impuras.
  • Comprensión de código : el comportamiento del código que depende de muchas variables globales mutables es mucho más difícil de entender: es necesario comprender el rango de posibles interacciones con la variable global antes de poder razonar sobre el comportamiento del código. . En algunas situaciones, este problema puede volverse intratable.
  • Problemas de concurrencia : el estado global mutable generalmente requiere algún tipo de bloqueo cuando se usa en una situación concurrente. Es muy difícil hacerlo bien (es una causa de errores) y agrega considerablemente más complejidad a su código (difícil / costoso de mantener).
  • Rendimiento : varios subprocesos que golpean continuamente el mismo estado global provocan la contención de la memoria caché y ralentizarán el sistema en general.

Alternativas al estado global mutable:

  • Parámetros de función : a menudo se pasan por alto, pero la mejor manera de evitar el estado global es parametrizar mejor sus funciones. Te obliga a resolver la importante pregunta conceptual: ¿qué información requiere esta función para hacer su trabajo? A veces tiene sentido tener una estructura de datos llamada "Contexto" que se puede pasar por una cadena de funciones que envuelve toda la información relevante.
  • Inyección de dependencia : igual que para los parámetros de función, solo se hizo un poco antes (en la construcción del objeto en lugar de en la invocación de la función). Sin embargo, tenga cuidado si sus dependencias son objetos mutables, esto puede causar rápidamente los mismos problemas que el estado global mutable .....
  • El estado global inmutable es en su mayoría inofensivo, es efectivamente una constante. ¡Pero asegúrate de que realmente sea una constante y de que no vas a tener la tentación de convertirla en un estado global mutable en un momento posterior!
  • Singletons inmutables : más o menos como un estado global inmutable, excepto que puede diferir la creación de instancias hasta que se necesiten. Útil para, por ejemplo, Grandes estructuras de datos fijos que requieren costosos cálculos previos únicos. Los singletons mutables son, por supuesto, equivalentes a un estado global mutable y, por lo tanto, son malvados :-)
  • Enlace dinámico : solo está disponible en algunos idiomas como Common Lisp / Clojure, pero esto efectivamente le permite enlazar un valor dentro de un alcance controlado (generalmente en base a subprocesos) que no afecta a otros subprocesos. Hasta cierto punto, esta es una forma "segura" de obtener el mismo efecto que una variable global, ya que sabe que solo se verá afectado el hilo de ejecución actual. Esto es particularmente útil en el caso de que tenga varios hilos, cada uno manejando transacciones independientes, por ejemplo.
respondido por el mikera 11.05.2012 - 03:18
fuente
57
  1. Ya que toda tu maldita aplicación puede estar usándola, siempre es increíblemente difícil tenerlos en cuenta. volver a salir de nuevo. Si alguna vez cambia algo relacionado con su global, todo su código debe cambiar. Esto es un dolor de cabeza de mantenimiento, mucho más que simplemente poder grep para el nombre de tipo para averiguar qué funciones lo utilizan.
  2. Son malos porque introducen dependencias ocultas, que rompen los subprocesos múltiples, lo que es cada vez más vital para cada vez más aplicaciones.
  3. El estado de la variable global siempre es completamente no confiable, ya que todo su código podría estar haciendo algo al respecto.
  4. Son muy difíciles de probar.
  5. Hacen difícil llamar a la API. "Debes recordar llamar a SET_MAGIC_VARIABLE () antes de llamar a la API" es solo rogar para que alguien se olvide de llamarla. Hace que el uso de la API sea propenso a errores, causando errores difíciles de encontrar. Al usarlo como un parámetro regular, obliga a la persona que llama a proporcionar un valor correctamente.

Simplemente pase una referencia a las funciones que lo necesiten. No es tan difícil.

    
respondido por el DeadMG 10.05.2012 - 21:42
fuente
31

Si dices "estado", generalmente se entiende que significa "estado mutable". Y el estado global mutable es totalmente malo, porque significa que cualquier parte del programa puede influir en cualquier otra parte (cambiando el estado global).

Imagine depurar un programa desconocido: la función A se comporta de cierta manera para ciertos parámetros de entrada, pero a veces funciona de manera diferente para los mismos parámetros. Encuentra que usa la variable global x .

Busca lugares que modifican x y encuentra que hay cinco lugares que lo modifican. Ahora, buena suerte, descubriendo en qué casos funciona la función A que hace ...

    
respondido por el sleske 10.05.2012 - 21:42
fuente
9

En cierto modo respondiste tu propia pregunta. Son difíciles de manejar cuando son "abusados", pero pueden ser útiles y [algo] predecibles cuando se usan adecuadamente, por alguien que sabe cómo contenerlos. El mantenimiento y los cambios a / en las redes globales suelen ser una pesadilla, que empeora a medida que aumenta el tamaño de la aplicación.

Los programadores experimentados que pueden distinguir la diferencia entre los globales son la única opción, y ellos la solución fácil, puede tener problemas mínimos al usarlos. Pero los interminables problemas posibles que pueden surgir con su uso requieren el consejo de no usarlos.

editar: para aclarar lo que quiero decir, los globales son impredecibles por naturaleza. Como con cualquier cosa impredecible, puede tomar medidas para contener la imprevisibilidad, pero siempre hay límites a lo que se puede hacer. Agregue a esto la molestia de que los nuevos desarrolladores que se unen al proyecto tengan que lidiar con variables relativamente desconocidas, las recomendaciones contra el uso de globales deben ser comprensibles.

    
respondido por el orourkek 10.05.2012 - 21:47
fuente
8

En primer lugar, para que la inyección de dependencia sea "con estado", necesitaría usar singletons, por lo que las personas que dicen que esto es de alguna manera una alternativa están equivocadas. Las personas usan objetos de contexto global todo el tiempo ... Incluso el estado de sesión, por ejemplo, es esencialmente una variable global. Pasar todo a su alrededor, ya sea por inyección de dependencia o no, no siempre es la mejor solución. Actualmente trabajo en una aplicación muy grande que usa muchos objetos de contexto global (singletons inyectados a través de un contenedor IoC) y nunca ha sido un problema depurar. Especialmente con una arquitectura dirigida por eventos, se puede preferir usar objetos de contexto global en lugar de pasar lo que haya cambiado. Depende a quien le preguntes.

Se puede abusar de cualquier cosa y también depende del tipo de aplicación. El uso de variables estáticas, por ejemplo, en una aplicación web es completamente diferente a una aplicación de escritorio. Si puedes evitar las variables globales, hazlo, pero a veces tienen sus usos. Como mínimo, asegúrese de que sus datos globales se encuentren en un objeto contextual claro. En cuanto a la depuración, nada que una pila de llamadas y algunos puntos de interrupción no puedan resolver.

Quiero enfatizar que el uso ciego de variables globales es una mala idea. Las funciones deben ser reutilizables y no debe importar de dónde provienen los datos; al referirse a las variables globales, se asocia la función con una entrada de datos específica. Esta es la razón por la que se debe pasar y la inyección de dependencia puede ser útil, aunque todavía se trata de un almacén de contexto centralizado (a través de singletons).

Btw ... Algunas personas piensan que la inyección de dependencia es mala, incluido el creador de Linq, pero eso no impedirá que la gente lo use, incluyéndome a mí. En definitiva la experiencia será tu mejor maestra. Hay momentos para seguir reglas y tiempos para romperlas.

    
respondido por el KingOfHypocrites 11.05.2012 - 14:48
fuente
7

Hay muchos problemas con Singletons, aquí están los dos problemas más grandes en mi mente.

  • Hace que las pruebas unitarias sean problemáticas. El estado global puede contaminarse de una prueba a la siguiente

  • Hace cumplir la regla de "Uno y solo uno", que, aunque no podría cambiar, de repente lo hace. Un montón de código de utilidad que utiliza el objeto accesible globalmente debe modificarse.

Habiendo dicho eso, la mayoría de los sistemas necesitan algo de Big Global Objects. Estos son elementos que son grandes y costosos (por ejemplo, administradores de conexión de base de datos), o que contienen información general del estado (por ejemplo, información de bloqueo).

La alternativa a un Singleton es tener estos Grandes Objetos Globales creados en el inicio y pasados como parámetros a todas las clases o métodos que necesitan acceso a este objeto.

El problema aquí es que terminas con un gran juego de "pase el paquete". Tiene un gráfico de los componentes y sus dependencias, y algunas clases crean otras clases, y cada una tiene que mantener un grupo de componentes de dependencia solo porque los componentes creados (o los componentes de los componentes generados) los necesitan.

Te encuentras con nuevos problemas de mantenimiento. Un ejemplo: de repente, su "WidgetFactory", componente del gráfico, necesita un objeto temporizador que desee simular. Sin embargo, "WidgetFactory" es creado por "WidgetBuilder" que forma parte de "WidgetCreationManager", y es necesario que tres clases conozcan este objeto de temporizador, aunque solo una lo use. Te encuentras con ganas de darte por vencido y volver a Singletons, y simplemente hacer que este objeto temporizador sea accesible globalmente.

Afortunadamente, este es exactamente el problema que se resuelve con un marco de inyección de dependencia. Simplemente puede decirle al marco qué clases necesita crear, y usa la reflexión para descubrir el gráfico de dependencia para usted, y construye automáticamente cada objeto cuando es necesario.

En resumen, los Singletons son malos y la alternativa es usar un marco de inyección de dependencia.

Resulta que uso Castle Windsor, pero tienes muchas opciones para elegir. Consulte esta página de 2008 para obtener una lista de los marcos disponibles.

    
respondido por el Andrew Shepherd 11.05.2012 - 08:45
fuente
3

Bueno, por un lado, puede ejecutar exactamente el mismo problema que puede hacer con singletons. Lo que hoy parece una "cosa global de la que solo necesito una" se convertirá repentinamente en algo que usted necesita más en el futuro.

Por ejemplo, hoy creas este sistema de configuración global porque quieres una configuración global para todo el sistema. Unos años después, se traslada a otro sistema y alguien dice "hey, sabes, esto podría funcionar mejor si hubiera una configuración global general y una configuración específica para una plataforma". De repente, tienes todo este trabajo para hacer que tus estructuras globales no sean globales, por lo que puedes tener varias.

(Esto no es un ejemplo aleatorio ... esto sucedió con nuestro sistema de configuración en el proyecto en el que estoy actualmente).

Teniendo en cuenta que el costo de hacer algo no global suele ser trivial, es una tontería hacerlo. Solo estás creando problemas futuros.

    
respondido por el Steven Burnap 10.05.2012 - 22:02
fuente
3

El otro problema es que hacen que una aplicación sea difícil de escalar porque no son lo suficientemente "globales". El alcance de una variable global es el proceso.

Si desea escalar su aplicación utilizando múltiples procesos o ejecutándose en múltiples servidores, no puede hacerlo. Al menos no hasta que hayas eliminado todos los globales y reemplazarlos con algún otro mecanismo.

    
respondido por el James Anderson 11.05.2012 - 03:45
fuente
3

Idiomas diseñados para seguridad y amp; El diseño robusto de sistemas a menudo se deshace del estado global mutable por completo. (Podría decirse que esto significa que no hay globales, ya que los objetos inmutables en cierto sentido no son realmente estadísticos, ya que nunca tienen una transición de estado).

Joe-E es un ejemplo, y David Wagner explica el decisión por lo tanto:

  

Análisis de quién tiene acceso a un objeto y el principio   de menor privilegio son ambos subvertidos cuando las capacidades son   Se almacenan en variables globales y por lo tanto son potencialmente legibles.   por cualquier parte del programa. Una vez que un objeto está disponible globalmente, ya no es posible limitar el alcance del análisis:   el acceso al objeto es un privilegio que no se puede retener   De cualquier código en el programa. Joe-E evita estos problemas   Al verificar que el alcance global no contiene capacidades,   solo datos inmutables.

Por lo tanto, una manera de pensarlo es

  1. La programación es un problema de razonamiento distribuido. Los programadores en grandes proyectos deben dividir el programa en partes que puedan ser razonadas por individuos.
  2. Cuanto menor sea el alcance, más fácil será razonar. Esto es cierto tanto para los individuos como para las herramientas de análisis estático que intentan probar las propiedades de un sistema y las pruebas que necesitan probar las propiedades de un sistema.
  3. Las fuentes de autoridad significativas que están disponibles globalmente hacen que las propiedades del sistema sean difíciles de razonar.

Por lo tanto, el estado globalmente mutable hace que sea más difícil

  1. diseñar sistemas robustos,
  2. más difícil de probar las propiedades de un sistema, y
  3. es más difícil asegurarse de que sus pruebas se estén realizando en un ámbito similar al de su entorno de producción.

El estado mutable global es similar a DLL hell . Con el tiempo, las diferentes piezas de un sistema grande requerirán un comportamiento sutilmente diferente de las piezas compartidas del estado mutable. Resolver el infierno de DLL y las inconsistencias de estados mutables compartidos requiere una coordinación a gran escala entre equipos dispares. Estos problemas no se producirían si el estado global hubiera sido correctamente orientado para comenzar.

    
respondido por el Mike Samuel 17.05.2012 - 21:21
fuente
2

Los globales no son tan malos. Como se indicó en varias otras respuestas, el problema real con ellas es que la ruta de la carpeta global puede ser, hoy, una de varias o incluso cientos. Si está escribiendo un programa rápido y único, use globals si es más fácil. En general, sin embargo, permitir los múltiplos incluso cuando solo crees que necesitas uno es el camino a seguir. No es agradable tener que reestructurar un gran programa complejo que de repente necesita hablar con dos bases de datos.

Pero no dañan la confiabilidad. Cualquier dato al que se haga referencia desde muchos lugares en su programa puede causar problemas si cambia inesperadamente. Los enumeradores se ahogan cuando la colección que están enumerando se modifica en la mitad de la enumeración. Los eventos de la cola de eventos pueden jugar una mala pasada. Los hilos siempre pueden causar estragos. Cualquier cosa que no sea una variable local o un campo inmutable es un problema. Los globales son este tipo de problema, pero no lo vas a solucionar al hacerlos no globales.

Si está a punto de escribir en un archivo y la ruta de la carpeta cambia, el cambio y la escritura deben estar sincronizados. (Como una de las mil cosas que podrían salir mal, digamos que usted toma la ruta, luego ese directorio se elimina, luego la ruta de la carpeta se cambia a un buen directorio, luego intenta escribir en el directorio eliminado). El problema existe si la ruta de la carpeta es global o es una de las mil que el programa está usando actualmente.

Hay un problema real con los campos a los que pueden acceder diferentes eventos en una cola, diferentes niveles de recursión o diferentes subprocesos. Para hacerlo simple (y simplista): las variables locales son buenas y los campos son malos. Pero los antiguos globales seguirán siendo campos, por lo que este problema (aunque de importancia crítica) no se aplica al estado Bueno o Malvado de los campos Globales.

Adición: Problemas de subprocesamiento múltiple:

(Tenga en cuenta que puede tener problemas similares con una cola de eventos o llamadas recursivas, pero el subprocesamiento múltiple es por mucho el peor). Considere el siguiente código:

if (filePath != null)  text = filePath.getName();

Si filePath es una variable local o algún tipo de constante, su programa no va a fallar cuando se ejecuta porque filePath es nulo. El cheque siempre funciona. Ningún otro hilo puede cambiar su valor. De lo contrario , no hay garantías. Cuando comencé a escribir programas de multiproceso en Java, recibí NullPointerExceptions en líneas como esta todo el tiempo. Cualquier otro hilo puede cambiar el valor en cualquier momento, y con frecuencia lo hacen. Como señalan otras respuestas, esto crea serios problemas para las pruebas. La declaración anterior puede funcionar mil millones de veces, pasarla a través de pruebas exhaustivas y exhaustivas, y luego explotar una vez en producción. Los usuarios no podrán reproducir el problema, y no volverá a suceder hasta que se hayan convencido de que estaban viendo cosas y lo olvidaron.

Los Globals definitivamente tienen este problema, y si puedes eliminarlos completamente o reemplazarlos con constantes o variables locales, eso es algo muy bueno. Si tiene un código sin estado ejecutándose en un servidor web, probablemente pueda hacerlo. Normalmente, todos los problemas de subprocesos múltiples pueden ser asumidos por la base de datos.

Pero si su programa tiene que recordar cosas de una acción del usuario a la siguiente, tendrá campos accesibles por cualquier subproceso en ejecución. Cambiar un campo global a uno no global no ayudará a la confiabilidad.

    
respondido por el RalphChapin 10.05.2012 - 23:55
fuente
2
  

¿Por qué el Estado global es tan malo?

Mutable El estado global es malo porque es muy difícil para nuestro cerebro tener en cuenta más de unos pocos parámetros a la vez y descubrir cómo se combinan tanto desde una perspectiva de tiempo como desde una perspectiva de valor hasta afectar algo

Por lo tanto, somos muy malos en depurar o probar un objeto cuyo comportamiento tiene más de unas pocas razones externas para ser modificado durante la ejecución de un programa. No digamos nada cuando tenemos que razonar acerca de docenas de estos objetos tomados juntos.

    
respondido por el guillaume31 11.05.2012 - 18:11
fuente
2

El estado es inevitable en cualquier aplicación real. Puede envolverlo como desee, pero una hoja de cálculo debe contener datos en las celdas. Puede hacer que los objetos de celda solo funcionen como interfaz, pero eso no restringe cuántos lugares pueden llamar a un método en la celda y cambiar los datos. Usted crea jerarquías de objetos completos para tratar de ocultar las interfaces, de modo que otras partes del código no puedan cambiar los datos de forma predeterminada. Eso no impide que una referencia al objeto que contiene se pase de forma arbitraria. Tampoco nada de eso elimina los problemas de concurrencia por sí mismo. Esto dificulta la proliferación del acceso a los datos, pero en realidad no elimina los problemas percibidos con los globales. Si alguien quiere modificar una parte del estado, lo hará de manera global o mediante una API compleja (esto más tarde desalentará, no impedirá).

La verdadera razón para no usar el almacenamiento global es evitar las colisiones de nombres. Si carga varios módulos que declaran el mismo nombre global, tiene un comportamiento indefinido (muy difícil de depurar porque las pruebas unitarias pasarán) o un error de vinculador (estoy pensando que C: ¿su vinculador advierte o falla en esto?).

Si desea reutilizar el código, debe poder tomar un módulo de otro lugar y no tener que pisar accidentalmente su global porque usaron uno con el mismo nombre. O si tiene suerte y recibe un error, no desea tener que cambiar todas las referencias en una sección de código para evitar la colisión.

    
respondido por el phkahler 11.05.2012 - 19:11
fuente
1

No voy a decir si las variables globales son buenas o malas, pero lo que voy a agregar a la discusión es decir que si no está utilizando el estado global, es probable que esté desperdiciando mucho de memoria, especialmente cuando se utiliza classess para almacenar sus dependencias en los campos.

Para el estado global, no hay tal problema, todo es global.

Por ejemplo: imagina un escenario siguiente: tienes una cuadrícula de 10x10 que está formada por la clase "Board" y "Tile".

Si desea hacerlo de la forma POO, probablemente pasará el objeto "Tablero" a cada "Azulejo". Digamos ahora que "Tile" tiene 2 campos de tipo "byte" que almacenan sus coordenadas. La memoria total que tomaría en la máquina de 32 bits para un mosaico sería (1 + 1 + 4 = 6) bytes: 1 para x coord, 1 para y coord y 4 para un puntero a la placa. Esto da un total de 600 bytes para la configuración de mosaicos 10x10

Ahora, en el caso de que el tablero esté en el ámbito global, un solo objeto accesible desde cada mosaico solo tendría que obtener 2 bytes de memoria por cada mosaico, que son los bytes de coordenadas x e y. Esto daría sólo 200 bytes.

Entonces, en este caso, obtienes 1/3 del uso de la memoria si solo usas el estado global.

Esto, además de otras cosas, creo que es una razón por la que el alcance global aún se mantiene en lenguajes de nivel relativamente bajo como C ++

    
respondido por el spectre 22.03.2014 - 13:51
fuente
1

Ya que algunas otras respuestas aquí hacen la distinción entre mutable y inmutable , me gustaría resumir que incluso inmutable las variables / configuraciones globales suelen ser una molestia .

Considera las preguntas:

  

... Digamos que necesito una configuración global para mi aplicación, por ejemplo, las rutas de la carpeta del sistema o las credenciales de la base de datos de toda la aplicación. ...

Correcto, para un programa pequeño, esto probablemente no sea un problema, pero tan pronto como haces esto con los componentes en un sistema más grande ligeramente , escribir pruebas automáticas de repente se vuelve más difícil porque todas las pruebas ( ~ ejecutándose dentro del mismo proceso) debe funcionar con el mismo valor de configuración global.

Si todos los datos de configuración se pasan explícitamente, los componentes se vuelven mucho más fáciles de probar y nunca tendrá que preocuparse de cómo arrancar un valor de configuración global para múltiples pruebas, tal vez incluso en paralelo.

    
respondido por el Martin Ba 30.06.2017 - 14:02
fuente
0

Cuando es fácil ver y acceder a todo el estado global, los programadores siempre terminan haciéndolo. Lo que obtienes es tácito y difícil de rastrear dependencias (int blahblah significa que array foo es válido en lo que sea). Esencialmente, hace que sea casi imposible mantener las invariantes del programa, ya que todo se puede modificar de forma independiente. someInt tiene una relación entre otherInt, eso es difícil de administrar y más difícil de probar si puedes cambiar directamente en cualquier momento.

Dicho esto, se puede hacer (mucho antes cuando era la única forma en algunos sistemas), pero esas habilidades se pierden. Se basan principalmente en las convenciones de codificación y nomenclatura, el campo ha avanzado por una buena razón. Su compilador y enlazador hacen un mejor trabajo al verificar las invariantes en los datos protegidos / privados de las clases / módulos que confiar en que los humanos sigan un plan maestro y lean la fuente.

    
respondido por el anon 11.05.2012 - 04:50
fuente
0

Hay varios factores a considerar con el estado global:

  1. espacio de memoria del programador
  2. Globales inmutables / escribir una vez globales.
  3. Globales mutables
  4. Dependencia de los globales.

Cuantos más globales tengas, mayor será la posibilidad de introducir duplicados, y así romper las cosas cuando los duplicados se desincronicen. Mantener a todos los globos globales en tu memoria humana falible se convierte en algo necesario y doloroso.

Los inmutables / escribir una vez están generalmente bien, pero tenga cuidado con los errores de secuencia de inicialización.

Los globales mutables a menudo se confunden con globales inmutables ...

Una función que usa globals efectivamente tiene parámetros extra "ocultos", lo que dificulta su refactorización.

El estado global no es malo, pero tiene un costo definido: úselo cuando el beneficio supere el costo.

    
respondido por el jmoreno 11.05.2012 - 14:19
fuente

Lea otras preguntas en las etiquetas