Por que o estado global é tão mal?

306

Antes de começarmos, deixe-me dizer que estou bem ciente dos conceitos de Abstração e Injeção de Dependência. Eu não preciso dos meus olhos abertos aqui.

Bem, a maioria de nós diz, (também) muitas vezes sem realmente entender, "Não use variáveis globais", ou "Singletons são ruins porque são globais". Mas o que é realmente tão ruim sobre o estado global ameaçador?

Digamos que eu precise de uma configuração global para meu aplicativo, por exemplo, caminhos de pastas do sistema ou credenciais de banco de dados de aplicativos.

Nesse caso, não vejo nenhuma boa solução além de fornecer essas configurações em algum tipo de espaço global, que estará normalmente disponível para todo o aplicativo.

Eu sei que é ruim abusar dele, mas é o espaço global realmente THAT evil? E se for, que boas alternativas existem?

    
por Madara Uchiha 10.05.2012 / 21:35
fonte

17 respostas

262

Muito brevemente, torna o estado do programa imprevisível.

Para elaborar, imagine que você tenha alguns objetos que usam a mesma variável global. Supondo que você não esteja usando uma fonte de aleatoriedade em nenhum dos módulos, a saída de um determinado método pode ser prevista (e, portanto, testada) se o estado do sistema for conhecido antes da execução do método.

No entanto, se um método em um dos objetos disparar um efeito colateral que altere o valor do estado global compartilhado, você não saberá mais qual é o estado inicial quando executar um método no outro objeto. Agora você não pode mais prever qual saída obterá quando executar o método e, portanto, não poderá testá-lo.

Em um nível acadêmico, isso pode não parecer tão sério, mas a capacidade de testar o código da unidade é um passo importante no processo de provar sua correção (ou pelo menos a adequação à finalidade).

No mundo real, isso pode ter algumas conseqüências muito sérias. Suponha que você tenha uma classe que preencha uma estrutura de dados global e uma classe diferente que consuma os dados nessa estrutura de dados, alterando seu estado ou destruindo-os no processo. Se a classe do processador executar um método antes que a classe populator termine, o resultado é que a classe do processador provavelmente terá dados incompletos para processar, e a estrutura de dados na qual a classe populadora estava trabalhando poderia ser corrompida ou destruída. O comportamento do programa nessas circunstâncias torna-se completamente imprevisível e provavelmente levará a perdas épicas.

Além disso, o estado global prejudica a legibilidade do seu código. Se o seu código tiver uma dependência externa que não seja explicitamente introduzida no código, quem conseguir a tarefa de manter seu código terá que procurá-lo para descobrir de onde veio.

Quanto a quais alternativas existem, bem é impossível não ter nenhum estado global, mas na prática geralmente é possível restringir o estado global a um único objeto que envolve todos os outros, e que nunca deve ser referenciado confiando em as regras de escopo da linguagem que você está usando. Se um objeto específico precisar de um estado particular, ele deverá explicitamente pedir por ele passado como um argumento para seu construtor ou por um método setter. Isso é conhecido como Injeção de Dependência.

Pode parecer bobo passar em um estado que você já pode acessar devido às regras de escopo de qualquer idioma que esteja usando, mas as vantagens são enormes. Agora, se alguém olha para o código isoladamente, fica claro o estado de que ele precisa e de onde vem. Ele também tem enormes benefícios em relação à flexibilidade do seu módulo de código e, portanto, as oportunidades de reutilizá-lo em diferentes contextos. Se o estado for passado e as alterações no estado forem locais para o bloco de código, você poderá passar em qualquer estado que desejar (se for o tipo de dados correto) e fazer com que seu código o processe. Código escrito neste estilo tende a ter a aparência de uma coleção de componentes fracamente associados que podem ser facilmente trocados. O código de um módulo não deve se importar de onde vem o estado, apenas como processá-lo. Se você passar o estado para um bloco de código, esse bloco de código pode existir isoladamente, o que não é o caso se você confiar no estado global.

Existem muitas outras razões pelas quais a aprovação do estado é muito superior à confiança no estado global. Esta resposta não é de forma abrangente. Você provavelmente poderia escrever um livro inteiro sobre por que o estado global é ruim.

    
por 10.05.2012 / 21:37
fonte
124

O estado global mutável é mal por muitas razões:

  • Bugs do estado global mutável - muitos bugs complicados são causados por mutabilidade. Bugs que podem ser causados por mutação em qualquer lugar do programa são ainda mais complicados, já que muitas vezes é difícil rastrear a causa exata
  • Má testabilidade - se você tiver um estado global mutável, precisará configurá-lo para quaisquer testes que escrever. Isso dificulta os testes (e as pessoas sendo pessoas são menos propensas a fazê-lo!). por exemplo. no caso de credenciais de banco de dados de aplicativos, e se um teste precisar acessar um banco de dados de teste específico diferente de todo o resto?
  • Inflexibilidade - e se uma parte do código exigir um valor no estado global, mas outra parte exigir outro valor (por exemplo, um valor temporário durante uma transação)? Você de repente tem um pouco de refatoração em suas mãos
  • Impureza de função - funções "puras" (ou seja, aquelas em que o resultado depende apenas dos parâmetros de entrada e não têm efeitos colaterais) são muito mais fáceis de raciocinar e compor para construir programas maiores. Funções que lêem ou manipulam estados globais mutáveis são inerentemente impuras.
  • Compreensão de código - o comportamento de código que depende de muitas variáveis globais mutáveis é muito mais complicado de entender - você precisa entender o intervalo de possíveis interações com a variável global antes de raciocinar sobre o comportamento do código . Em algumas situações, esse problema pode se tornar intratável.
  • Problemas de concorrência - o estado global mutável geralmente requer alguma forma de bloqueio quando usado em uma situação concorrente. Isso é muito difícil de acertar (é uma causa de bugs) e adiciona consideravelmente mais complexidade ao seu código (difícil / caro para manter).
  • Desempenho - vários encadeamentos continuamente no mesmo estado global causam contenção de cache e retardam o sistema como um todo.

Alternativas para o estado global mutável:

  • Parâmetros de função - geralmente ignorados, mas a melhor parametrização de suas funções geralmente é a melhor maneira de evitar o estado global. Obriga você a resolver a importante questão conceitual: quais informações esta função requer para realizar seu trabalho? Às vezes, faz sentido ter uma estrutura de dados chamada "Contexto" que possa ser passada por uma cadeia de funções que encerre todas as informações relevantes.
  • Injeção de dependência - o mesmo que para os parâmetros de função, feito um pouco antes (na construção do objeto em vez da invocação da função). Tenha cuidado se suas dependências forem objetos mutáveis, mas isso pode causar rapidamente os mesmos problemas que um estado global mutável.
  • Estado global imutável é praticamente inofensivo - é efetivamente uma constante. Mas certifique-se de que é realmente uma constante, e que você não será tentado a transformá-lo em estado global mutável em um momento posterior!
  • Inimitáveis singletons - praticamente o mesmo que um estado global imutável, exceto que você pode adiar a instanciação até que eles sejam necessários. Útil para, e. grandes estruturas de dados fixas que precisam de pré-cálculo caro e único. Singletons mutáveis são obviamente equivalentes a estados globais mutáveis e são, portanto, malignos: -)
  • Ligação dinâmica - disponível apenas em alguns idiomas como Common Lisp / Clojure, mas isso efetivamente permite vincular um valor dentro de um escopo controlado (geralmente em uma base de thread local) que não afeta outros threads. Até certo ponto, essa é uma maneira "segura" de obter o mesmo efeito que uma variável global, já que você sabe que apenas o segmento atual de execução será afetado. Isso é particularmente útil no caso em que você tem vários encadeamentos, cada um manipulando transações independentes, por exemplo.
por 11.05.2012 / 03:18
fonte
57
  1. Como todo o seu maldito aplicativo pode usá-lo, é sempre incrivelmente difícil considerá-los de volta novamente. Se você alguma vez mudou alguma coisa com o seu global, todo o seu código precisa mudar. Isso é uma dor de cabeça de manutenção - muito mais do que simplesmente ser capaz de grep para o nome do tipo para descobrir quais funções o usam.
  2. Eles são ruins porque introduzem dependências ocultas, que quebram o multithreading, que é cada vez mais vital para cada vez mais aplicativos.
  3. O estado da variável global é sempre completamente não confiável, porque todo o seu código pode estar fazendo alguma coisa.
  4. Eles são muito difíceis de testar.
  5. Eles dificultam a chamada da API. "Você deve se lembrar de chamar SET_MAGIC_VARIABLE () antes de chamar API" é apenas implorando para alguém esquecer de chamá-lo. Isso torna o uso da API propenso a erros, causando bugs difíceis de localizar. Ao usá-lo como um parâmetro regular, você força o chamador a fornecer um valor adequadamente.

Basta passar uma referência para as funções que precisam dela. Não é tão difícil assim.

    
por 10.05.2012 / 21:42
fonte
32

Se você disser "estado", isso geralmente significa "estado mutável". E o estado global mutável é totalmente maligno, porque significa que qualquer parte do programa pode influenciar qualquer outra parte (alterando o estado global).

Imagine a depuração de um programa desconhecido: Você descobre que a função A se comporta de determinada maneira para certos parâmetros de entrada, mas às vezes funciona de maneira diferente para os mesmos parâmetros. Você acha que ele usa a variável global x .

Você procura lugares que modificam x e descobre que há cinco lugares que o modificam. Agora boa sorte em descobrir em quais casos a função A faz o que ...

    
por 10.05.2012 / 21:42
fonte
9

Você meio que respondeu sua própria pergunta. Eles são difíceis de gerenciar quando "abusados", mas podem ser úteis e [um pouco] previsíveis quando usados adequadamente, por alguém que saiba como contê-los. Manutenção e mudanças para / nos globais geralmente é um pesadelo, agravado à medida que o tamanho do aplicativo aumenta.

Programadores experientes que podem dizer a diferença entre globals sendo a única opção, e eles sendo a solução fácil, can tem problemas mínimos usando-os. Mas as infinitas questões possíveis que podem surgir com o seu uso exigem o conselho contra usá-las.

edit: Para esclarecer o que quero dizer, globals são imprevisíveis por natureza. Como com qualquer coisa imprevisível, você pode tomar medidas para conter a imprevisibilidade, mas sempre há limites para o que pode ser feito. Adicione a isso o incômodo de novos desenvolvedores que se juntam ao projeto tendo que lidar com variáveis relativamente desconhecidas, as recomendações contra o uso de globals devem ser compreensíveis.

    
por 10.05.2012 / 21:47
fonte
8
Primeiro de tudo, para injeção de dependência para ser "stateful", você precisaria usar singletons, então as pessoas dizendo isso é de alguma forma uma alternativa estão enganados. As pessoas usam objetos de contexto global o tempo todo ... Mesmo o estado da sessão, por exemplo, é essencialmente uma variável global. Passar tudo por injeção de dependência ou não é sempre a melhor solução. Eu trabalho em um aplicativo muito grande atualmente que usa um monte de objetos de contexto global (singletons injetados através de um contêiner IoC) e nunca foi um problema para depurar. Especialmente com uma arquitetura orientada a eventos, pode ser preferível usar objetos de contexto global, passando por tudo o que foi alterado. Depende de quem você pergunta.

Tudo pode ser abusado e também depende do tipo de aplicativo. Usar variáveis estáticas, por exemplo, em um aplicativo da web é completamente diferente de um aplicativo de desktop. Se você puder evitar variáveis globais, faça isso, mas às vezes elas têm seus usos. No mínimo, certifique-se de que seus dados globais estejam em um objeto contextual claro. No que diz respeito à depuração, nada que uma pilha de chamadas e alguns pontos de interrupção não possam resolver.

Eu quero enfatizar que cegamente usar variáveis globais é uma má ideia. As funções devem ser reutilizáveis e não devem se importar de onde os dados vêm - referindo-se a variáveis globais que combinam a função com uma entrada de dados específica. É por isso que deve ser transmitido e por que a injeção de dependência pode ser útil, embora você ainda esteja lidando com um armazenamento de contexto centralizado (via singletons).

Btw ... Algumas pessoas acham que a injeção de dependência é ruim, incluindo o criador do Linq, mas isso não vai impedir as pessoas de usá-lo, inclusive eu. Em última análise, a experiência será seu melhor professor. Há momentos em seguir regras e horários para quebrá-las.

    
por 11.05.2012 / 14:48
fonte
7

Existem muitos problemas com Singletons - aqui estão os dois maiores problemas em minha mente.

  • Isso torna o teste de unidade problemático. O estado global pode ser contaminado de um teste para o próximo

  • Ele impõe a regra difícil "Um-e-apenas-um", que, embora não possa ser alterada, acontece de repente. Um monte de códigos de utilitários que usaram o objeto globalmente acessível precisam ser alterados.

Dito isto, a maioria dos sistemas tem alguma necessidade de Big Global Objects. Esses itens são grandes e caros (por exemplo, gerenciadores de conexão de banco de dados) ou mantêm informações de estado abrangentes (por exemplo, informações de bloqueio).

A alternativa para um Singleton é ter esses Big Global Objects criados na inicialização e passados como parâmetros para todas as classes ou métodos que precisam de acesso a esse objeto.

O problema aqui é que você acaba com um grande jogo de "pass-the-parcel". Você tem um gráfico de componentes e suas dependências, e algumas classes criam outras classes, e cada uma delas precisa conter um monte de componentes de dependência apenas porque seus componentes gerados (ou os componentes dos componentes gerados) precisam deles.

Você se depara com novos problemas de manutenção. Um exemplo: de repente, seu componente "WidgetFactory", no fundo do gráfico, precisa de um objeto temporizador que você queira reproduzir. No entanto, "WidgetFactory" é criado pelo "WidgetBuilder", que faz parte do "WidgetCreationManager", e você precisa ter três classes sabendo sobre este objeto timer, mesmo que apenas um realmente o use. Você se encontra querendo desistir e voltar para Singletons, e apenas tornar este objeto temporário globalmente acessível.

Felizmente, esse é exatamente o problema resolvido por uma estrutura de injeção de dependência. Você pode simplesmente dizer ao framework quais classes ele precisa criar, e ele usa a reflexão para descobrir o gráfico de dependência para você, e automaticamente constrói cada objeto quando eles são necessários.

Então, em resumo, Singletons são ruins, e a alternativa é usar uma estrutura de Injeção de Dependência.

Por acaso eu uso o Castelo Windsor, mas você é mimado pela escolha. Veja esta página de volta em 2008 para uma lista de frameworks disponíveis.

    
por 11.05.2012 / 08:45
fonte
3

Bem, por um lado, você pode correr para exatamente o mesmo problema que você pode com singletons. O que hoje parece ser uma "coisa global que eu só preciso de um" de repente se transformará em algo que você precisa mais no caminho.

Por exemplo, hoje você cria este sistema de configuração global porque deseja uma configuração global para todo o sistema. Alguns anos mais adiante, você porta para outro sistema e alguém diz "Ei, você sabe, isso pode funcionar melhor se houvesse uma configuração global geral e uma configuração específica de plataforma". De repente, você tem todo esse trabalho para tornar suas estruturas globais não globais, então você pode ter várias estruturas.

(Este não é um exemplo aleatório ... isso aconteceu com o nosso sistema de configuração no projeto em que estou atualmente.)

Considerando que o custo de fazer algo não global é geralmente trivial, é bobagem fazê-lo. Você está apenas criando problemas futuros.

    
por 10.05.2012 / 22:02
fonte
3

O outro problema, curiosamente, é que eles dificultam a escalação de um aplicativo, porque eles não são "globais" o suficiente. O escopo de uma variável global é o processo.

Se você quiser escalonar seu aplicativo usando vários processos ou executando em vários servidores, não é possível. Pelo menos não até você fatorar todos os globals e substituí-los por algum outro mecanismo.

    
por 11.05.2012 / 03:45
fonte
3

Idiomas criados para proteger & O design robusto de sistemas geralmente se livra do estado global mutável . (Indiscutivelmente, isso significa que não há globais, já que os objetos imutáveis não são, em certo sentido, verdadeiros, porque nunca têm uma transição de estado.)

Joe-E é um exemplo, e David Wagner explica o decisão assim:

Analysis of who has access to an object and the principle of least privilege are both subverted when capabilities are stored in global variables and thus are potentially readable by any part of the program. Once an object is globally available, it is no longer possible to limit the scope of analysis: access to the object is a privilege that cannot be withheld from any code in the program. Joe-E avoids these problems by verifying that the global scope contains no capabilities, only immutable data.

Então, uma maneira de pensar sobre isso é

  1. A programação é um problema de raciocínio distribuído. Os programadores em grandes projetos precisam dividir o programa em partes que podem ser raciocinadas por indivíduos.
  2. Quanto menor o escopo, mais fácil é raciocinar. Isso é verdade tanto para indivíduos quanto para ferramentas de análise estática que tentam provar as propriedades de um sistema e de testes que precisam testar as propriedades de um sistema.
  3. Fontes significativas de autoridade que estão disponíveis globalmente tornam as propriedades do sistema difíceis de avaliar.

Portanto, o estado globalmente mutável torna mais difícil

  1. projetam sistemas robustos,
  2. mais difícil provar propriedades de um sistema e
  3. mais difícil ter certeza de que seus testes estão sendo testados em um escopo semelhante ao seu ambiente de produção.

O estado mutável global é semelhante ao inferno da DLL . Com o tempo, diferentes partes de um sistema grande exigirão comportamentos sutilmente diferentes de partes compartilhadas do estado mutável. Resolver erros de DLL e inconsistências de estado mutável compartilhado requer uma coordenação em grande escala entre equipes diferentes. Esses problemas não ocorreriam se o estado global tivesse sido adequadamente definido para começar.

    
por 17.05.2012 / 21:21
fonte
2

Globals não são tão ruins assim. Como afirmado em várias outras respostas, o problema real com elas é que o que é, hoje, o caminho da pasta global pode ser um dos vários, ou até mesmo centenas. Se você estiver escrevendo um programa rápido e único, use globals se for mais fácil. Geralmente, porém, permitir múltiplos, mesmo quando você só pensa que precisa de um, é o caminho a percorrer. Não é agradável reestruturar um programa grande e complexo que, de repente, precisa falar com dois bancos de dados.

Mas eles não prejudicam a confiabilidade. Quaisquer dados referenciados em muitos lugares no seu programa podem causar problemas se forem alterados inesperadamente. Enumeradores sufocam quando a coleção que estão enumerando é alterada na enumeração média. Os eventos da fila de eventos podem reproduzir truques um no outro. Tópicos sempre podem causar estragos. Qualquer coisa que não seja uma variável local ou campo imutável é um problema. Globals são esse tipo de problema, mas você não vai consertar isso tornando-os não globais.

Se você estiver prestes a gravar em um arquivo e o caminho da pasta mudar, a alteração e a gravação precisarão ser sincronizadas. (Como uma das milhares de coisas que poderiam dar errado, digamos que você pegue o caminho, então esse diretório é excluído, então o caminho da pasta é alterado para um bom diretório, então você tenta escrever no diretório excluído.) O problema existe o caminho da pasta é global ou é um dos milhares que o programa está usando atualmente.

Existe um problema real com campos que podem ser acessados por diferentes eventos em uma fila, diferentes níveis de recursão ou diferentes encadeamentos. Para simplificar (e simplista): as variáveis locais são boas e os campos são ruins. Mas ex-globals ainda serão campos, então essa questão (ainda que criticamente importante) não se aplica ao status Good or Evil dos campos Global.

Adição: Problemas com multithreading:

(Observe que você pode ter problemas semelhantes com uma fila de eventos ou chamadas recursivas, mas o multithreading é de longe o pior.) Considere o seguinte código:

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

Se filePath for uma variável local ou algum tipo de constante, o seu programa não falhará durante a execução porque filePath é nulo. O cheque sempre funciona. Nenhum outro segmento pode alterar seu valor. Caso contrário , não há garantias. Quando comecei a escrever programas multithread em Java, recebi NullPointerExceptions em linhas como essa o tempo todo. Qualquer outro segmento pode alterar o valor a qualquer momento, e geralmente o fazem. Como várias outras respostas apontam, isso cria sérios problemas para testes. A declaração acima pode funcionar um bilhão de vezes, obtendo-se através de testes abrangentes e abrangentes, e depois explodir uma vez na produção. Os usuários não conseguirão reproduzir o problema e isso não acontecerá novamente até que eles se convençam de que estão vendo as coisas e o tenham esquecido.

Globals definitivamente tem esse problema, e se você puder eliminá-los completamente ou substituí-los por constantes ou variáveis locais, isso é uma coisa muito boa. Se você tiver código sem estado em execução em um servidor da Web, provavelmente conseguirá. Normalmente, todos os seus problemas de multithreading podem ser tomados pelo banco de dados.

Mas se o seu programa tiver que lembrar de coisas de uma ação do usuário para outra, você terá campos acessíveis por qualquer encadeamento em execução. Alternar um global para um campo não global não ajudará na confiabilidade.

    
por 10.05.2012 / 23:55
fonte
2

Why is Global State so Evil?

Mutável estado global é mau porque é muito difícil para o nosso cérebro ter em conta mais do que alguns parâmetros de cada vez e descobrir como eles combinam ambos de uma perspectiva de tempo e uma perspectiva de valor afeta alguma coisa.

Portanto, somos muito ruins em depurar ou testar um objeto cujo comportamento tem mais do que alguns motivos externos a serem alterados durante a execução de um programa. Muito menos quando temos que raciocinar sobre dezenas desses objetos juntos.

    
por 11.05.2012 / 18:11
fonte
2

O estado é inevitável em qualquer aplicação real. Você pode envolvê-lo da maneira que quiser, mas uma planilha deve conter dados nas células. Você pode criar objetos de célula com apenas funções como uma interface, mas isso não restringe a quantidade de locais que podem chamar um método na célula e alterar os dados. Você constrói hierarquias de objetos inteiros para tentar ocultar interfaces, de modo que outras partes do código não possam alterar os dados por padrão. Isso não impede que uma referência ao objeto contido seja passada arbitrariamente. Nem nada disso elimina problemas de simultaneidade por si só. Isso dificulta a proliferação de acesso a dados, mas na verdade não elimina os problemas percebidos com globals. Se alguém quiser modificar um pedaço de estado, ele fará isso globalmente ou por meio de uma API complexa (o mais tardar apenas desencorajará, não impedirá).

A verdadeira razão para não usar o armazenamento global é evitar colisões de nomes. Se você carregar vários módulos que declaram o mesmo nome global, você tem um comportamento indefinido (muito difícil de depurar porque testes de unidade passarão) ou um erro de vinculador (estou pensando C - seu vinculador avisa ou falha nisso?).

Se você quiser reutilizar o código, você precisa ser capaz de pegar um módulo de outro lugar e não tê-lo acidentalmente pisando no seu global porque eles usaram um com o mesmo nome. Ou, se você tiver sorte e receber um erro, não será necessário alterar todas as referências em uma seção do código para evitar a colisão.

    
por 11.05.2012 / 19:11
fonte
1

Não vou dizer se as variáveis globais são boas ou ruins, mas o que vou acrescentar à discussão é dizer que, se você não está usando o estado global, provavelmente está perdendo muito de memória, especialmente quando você usa classess para armazenar suas dependências em campos.

Para o estado global, não existe tal problema, tudo é global.

Por exemplo: imagine um cenário a seguir: Você tem uma grade de 10x10 que é feita de "Board" e "Tile" sem classe.

Se você quiser fazê-lo da maneira OOP, provavelmente passará o objeto "Board" para cada "Tile". Vamos dizer agora que "Tile" tem 2 campos do tipo "byte" que armazenam sua coordenada. A memória total que levaria na máquina de 32 bits para um bloco seria (1 + 1 + 4 = 6) bytes: 1 para x coord, 1 para y coord e 4 para um ponteiro para o quadro. Isto dá um total de 600 bytes para configuração de 10x10 tiles

Agora, para o caso em que a placa está no escopo global, um único objeto acessível a partir de cada bloco, você só precisaria obter 2 bytes de memória por cada bloco, ou seja, os bytes das coordenadas xey. Isso daria apenas 200 bytes.

Portanto, nesse caso, você obtém 1/3 do uso da memória, se você usar somente o estado global.

Isso, além de outras coisas, eu acho que é uma razão pela qual o escopo global ainda permanece em linguagens (relativamente) de baixo nível como C ++

    
por 22.03.2014 / 13:51
fonte
1

Como algumas outras respostas aqui fazem a distinção entre o estado global mutável e imutável , eu gostaria de opinar que mesmo imutável Variáveis globais / configurações são muitas vezes um aborrecimento .

Considere a pergunta:

... Let's say I need a global configuration for my application, for instance system folder paths, or application-wide database credentials. ...

Certo, para um programa pequeno, isso provavelmente não é um problema, mas assim que você faz isso com componentes em um sistema ligeiramente maior, escrever testes automatizados torna-se mais difícil porque todos os testes ( ~ rodando dentro do mesmo processo) deve funcionar com o mesmo valor de configuração global.

Se todos os dados de configuração forem passados explicitamente, os componentes ficarão muito mais fáceis de testar e você nunca precisará se preocupar em como inicializar um valor de configuração global para vários testes, talvez até em paralelo.

    
por 30.06.2017 / 14:02
fonte
0

Quando é fácil ver e acessar todo o estado global, os programadores invariavelmente acabam fazendo isso. O que você obtém é indizível e difícil de rastrear dependências (int blahblah significa que array foo é válido em qualquer coisa). Essencialmente, torna quase impossível manter invariantes de programas, pois tudo pode ser alternado independentemente. someInt tem um relacionamento entre o otherInt, que é difícil de gerenciar e mais difícil de provar se você pode alterar diretamente a qualquer momento.

Dito isto, isso pode ser feito (desde quando era o único caminho em alguns sistemas), mas essas habilidades são perdidas. Eles giram principalmente em torno de convenções de codificação e nomenclatura - o campo avançou por um bom motivo. Seu compilador e linker fazem um trabalho melhor de verificar invariantes em dados protegidos / privados de classes / módulos do que confiar em humanos para seguir um plano mestre e ler a fonte.

    
por 11.05.2012 / 04:50
fonte
0

Existem vários fatores a considerar com o estado global:

  1. Espaço de memória do programador
  2. Globais imutáveis / escrevem uma vez globais.
  3. Globals mutáveis
  4. Dependência de globals.

Quanto mais globais você tiver, maior a chance de introduzir duplicatas e, assim, quebrar as coisas quando as duplicatas ficarem fora de sincronia. Manter todos os globais na sua falível memória humana torna-se necessário e doloroso.

Imutáveis / escrever uma vez são geralmente OK, mas atente para erros de seqüência de inicialização.

Globals mutáveis são frequentemente confundidos com globals imutáveis…

Uma função que usa globals efetivamente possui parâmetros extras "ocultos", tornando a refatoração mais difícil.

O estado global não é mau, mas tem um custo definido - use-o quando o benefício supera o custo.

    
por 11.05.2012 / 14:19
fonte