Los puntos críticos son muchos, pero ya que no quiero escribir ni un poema ni un libro sobre el tema, he aislado unos pocos. Vamos a ver:
1) Las variables globales no son thread-safe: en la programación multihilo el uso de variables globales puede generar unos mal funcionamientos sutiles y difíciles de encontrar. El caso clásico es la instrucción de lectura/escritura de una global fuera de un área crítica, o sea (por ejemplo) sin la protección de un mutex: en un proyecto de gran envergadura es suficiente un olvido (sólo uno!) de este tipo para darte tantos dolores de cabeza que dejaras de usar las globales para el resto de tu vida como programador. Ver para creer. En este punto, se podría objetar: "Pero yo estoy escribiendo programas normales, no multihilo". Muy bien, declarando previamente (y matizando en la siguiente sección) que un programa "normal" se puede considerar un programa multi-hilo con un solo hilo, doy las gracias por la objeción, que me permite de lanzar el punto 2:
2) las variables globales violan el principio de mantenimiento/reutilización del Software: cuando se escribe profesionalmente Software siempre se debe pensar en el trabajo en equipo, y por lo tanto, en las operaciones de mantenimiento que podrían ser realizadas por otras personas (y, a veces) después de un largo tiempo. Evidentemente, un código, vasto y lleno de globales, es difícil de mantener como un código No Comment (¿recordáis?), porque el historial de una global es poco comprensible, podría verse afectado en muchos lugares diferentes por muchas funciones diferentes, y si para entender un trozo de código tienes que abrir decenas de archivos... os habeis ganado otro dolor de cabeza! Y no hablamos de reutilizar código lleno de globales para otro proyecto: si no lo habéis hecho nunca por lo menos tratar de imaginar la dificultad. Y no sólo: volvemos al punto 1 (thread-safe): ¿quién me dice que el codigo "normal" no tiene que volverse a utilizar (un día) en un proyecto multihilo? Si el código es thread-safe se puede hacer fácilmente, pero si hay globales de por medio... Bueno, buen trabajo (y buena suerte).
3) las variables globales aumentan la dificultad de depuración y multiplican la probabilidad de errores de programación: para la depuración, remito al punto 2: si el valor de una variable es difícil de seguir en términos de mantenimiento también lo será a nivel de depurar. Y habrá más mal funcionamientos para depurar (fantástico!), porque, además de todos los posibles errores de codificación. hay que añadir los de scope: probar este código:
int my_var = 0; void incrementaMyVar() { my_var += 5; } int main(int argc, char **argv) { // hago mil cosas... // ... // incremento my_var incrementaMyVar(); // hago otras mil cosas... // ... // declaro una "nueva" variable my var y la uso int my_var = 2; // ah, ah, ah: redeclaración! // ... // hago todavía mil cosas... // ... // incremento y test my_var (oops! cual my_var?) incrementaMyVar(); if (my_var == 2) formatMyHardDisk(); // uh, uh, uh: era la equivocada! // ... return 0; }El que se ha enseñado arriba era un problema de scope con redefinición local (accidental) de una global. El código que sigue es aún más simple, muestra un descuido de un detalle importante:
int my_var = 0; void hagoMilCosas() { // hago mil cosas... // ... // incremento my_var (escondido entre mil instrucciones!) my_var += 5; // hago otras mil cosas... // ... } int main(int argc, char **argv) { // hago unas cuantas cosas... // ... // llamo hagoMilCosas() hagoMilCosas(); // oops! he incrementado my_var sin quererlo // hago otras cosas... // ... // test my_var if (my_var == 5) formatMyHardDisk(); // uh, uh, uh: me he equivocado? // ... return 0; }buena historia, eh?
4) las variables globales violan el principio de encapsulación de variables: bien, esto ni siquiera es necesario que lo explique, una global es cualquier cosa menos que encapsulada... oops, pero esto es OOP, entonces un poco fuera del tema del blog: perdón, quería exagerar. Bueno, ya que estamos hablando de OOP, y entonces de C++, cito con gran placer el grande M.Cline que en su C++FAQ dice (traduzco, vale);
El nombre de una variable global debe empezar con //. Esta es la forma ideal de declarar una variable global: // int xyz; <-lo que hace ideal esta global es la inicial // Esta es la manera ideal de utilizar una variable global: void mycode() { ... // hace_algo_con(xyz); <-ídem ... } OK, esto es un juego. Casi. La verdad es que hay casos en que las variables globales son menos peores que la alternativa - cuando las globales son el menor de los males. Pero ellas son siempre malvadas. Así que lavarse las manos después del uso. Dos veces.Palabras santas.
Sin embargo, si pensáis que todo esto es sólo harina de mi bolsa, intentar pedirle a nuestro amigo Google: global variable are evil? y vais a ver que avalancha de resultados sale. Si estáis interesados en una de las páginas más interesantes la podéis encontrar aquí.
Creo que lo que se ha dicho es suficiente. Obviamente estoy un poco sesgado porque he trabajado mucho sobre software multihilo (y todavía tengo un poco de dolor de cabeza ...), pero os pido que confíeis y difundáis el mensaje lo más posible. Sí, lo sé, decirle a un programador sin experiencia (o a un programador cansado) "no usar variables globales" es como decirle a un niño "no comer demasiados dulces": bueno, hay que hacerlo. La salud en primer lugar.
Hasta el próximo post.