Contexto de solicitação global - antipadrão?

12

Hoje eu estava conversando com um colega sobre estruturas da Web Python e nossas impressões sobre elas. Eu disse a ele que acho que o Flask com uma solicitação global cheira muito mal e é um anti-padrão.

Os documentos dizem sobre o contexto da solicitação:

Por outro lado, durante o tratamento de solicitações, existem outras regras:

  • enquanto uma solicitação está ativa, os objetos locais de contexto (flask.request e outros) apontam para a solicitação atual.
  • qualquer código pode se apossar desses objetos a qualquer momento.

Acho que entendo a idéia por trás dessa decisão de design - para simplificar o aplicativo. É apenas um compromisso, como no caso dos Thread Locals :

Sim, geralmente não é uma idéia tão brilhante usar os locais de threads. Eles causam problemas para servidores que não são baseados no conceito de encadeamentos e dificultam a manutenção de aplicativos grandes. No entanto, o Flask simplesmente não foi projetado para aplicativos grandes ou servidores assíncronos. O Flask deseja tornar rápido e fácil escrever um aplicativo da web tradicional.

O patch de um objeto global com as informações atuais da solicitação é um antipadrão?

Acredito que sim, porque, na visão do analisador de código estático, é um estado global, embora não seja. E eu, como programador, não vou entender como isso funciona sem ler os documentos com atenção. E isso tem consequências nos testes .

Não é uma boa prática passar a solicitação como argumento para visualizações? Eu acho que é mais legível, explícito e mais fácil de depurar. E evita o estado global.

warvariuc
fonte
2
Você realmente não declarou quais seriam os efeitos negativos específicos de um antipadrão assim. Desconfio de generalidades radicais que não têm base factual.
9788 Robert Harvey
2
Boa pergunta, mas infelizmente não muitas respostas de qualidade
sleepycal

Respostas:

4

Muitas estruturas da web têm a mesma estrutura: uma solicitação global. Em certo sentido, é a coisa certa a fazer, porque, na verdade, existe apenas uma solicitação por vez.

Então, há algum ponto em passar a solicitação como um parâmetro? Não. A solicitação é a solicitação, e os parâmetros são para passar coisas diferentes em momentos diferentes.

O verdadeiro problema surge quando você começa a considerar níveis mais baixos de um aplicativo maior. Com uma solicitação global, existe a tentação de escrever código em todo o lugar que acessa a solicitação globalmente. Isso é uma coisa muito ruim . Produz acoplamento entre diferentes partes do código, dificulta a alteração e dificulta o teste.

Então, minha resposta é: mantenha a solicitação global e viva com ela. No entanto, sempre que um módulo ou função individual não precisar de toda a solicitação, passe apenas os dados necessários como parâmetro. Passe apenas o referenciador, o URL ou a cauda do comando e os bits necessários para suas funções. Isso ajudará a manter o código modular, reduzir o acoplamento e melhorar a capacidade de teste.

Para programas pequenos, pouco importa, mas para programas maiores isso pode ser um verdadeiro salva-vidas.

david.pfx
fonte
3

(Vou ficar em negrito e fazer disso uma resposta, embora possa ter alguns votos negativos.)

O balão é uma microestrutura; você se beneficia da simplicidade ao desistir de frescuras. Embora eu concorde com você no nível do intestino, eu sei que usei o balão + gunicorn em uma loja para me fornecer o multithreading de que eu precisava. Funcionou muito bem. Cada instância do script apenas entregou uma solicitação (ou seja, um thread) e o gunicorn tratou o "fan out" entre vários threads. Foi ótimo nisso.

Portanto, a desvantagem percebida que você está sentindo - que vários segmentos podem disputar o estado global - simplesmente não é um problema, porque é um script por segmento.

(Aqui é onde posso ter problemas) A segmentação e a simultaneidade são diferentes no mundo Python, e se você pensar nisso com um espírito de Java, é difícil incorporá-la. Minha experiência foi sobre os problemas de simultaneidade que resolvi concedidas em Java ou que são tratadas de forma transparente pelo contêiner do aplicativo, estão muito mais próximas da superfície no Python.

Era estranho para mim que um thread lidasse com uma invocação do meu script, mas depois que algumas dúzias rodavam em uma caixa ao mesmo tempo, me senti melhor com isso.

Roubar
fonte
4
Não estou preocupado com a segurança dos fios e tal. Acredito que o Flask funcione bem nesses casos. Minha pergunta é sobre design e arquitetura de aplicativos. Não é uma boa prática passar a solicitação como argumento para visualizações? Eu acho que é mais legível, explícito e mais fácil de depurar.
warvariuc
2

No Python, você tem o printcomando (função desde a v3) que imprime na saída padrão. Você não especifica explicitamente que deseja imprimir em STDOUT - isso é feito para você implicitamente nos bastidores.

Implicitamente. Em Python. E ninguém tem um problema com isso. Por quê?

printfaz parte da linguagem Python, e um requisito de programação em Python é ... bem ... conhecer Python. E se você conhece Python, sabe que printtem como alvo STDOUT. Não há surpresas lá.

Python - como linguagem - pode definir sua própria convenção e assumir que os programadores estão cientes deles.

As estruturas também desfrutam desse privilégio - essa é uma das principais diferenças entre uma estrutura e uma biblioteca. Você não precisa aprender uma biblioteca para usá-la - você só precisa encontrar a parte da API que precisa e assumir que ela segue as convenções da linguagem (ou estrutura). É por isso que você não vê recrutadores procurando pessoas com conhecimento no GSON ou no Apache Commons. Mas você vê recrutadores procurando pessoas com experiência em JQuery ou Ruby on Rails ou ASP.NET MVC - porque essas são estruturas que definem suas próprias convenções que você precisa aprender e estar ciente.

O Flask, como estrutura, pode definir uma convenção para armazenar o contexto em um segmento global local - e não deve surpreender ninguém, por isso não é um antipadrão.

Idan Arye
fonte
2
Observe que "stdout" significa qualquer descritor de arquivo apontado por sys.stdout. Se você mudar isso, a impressão vai para outro lugar.
Phoshi 11/03/14
1
Além disso, você pode substituir o fluxo de saída usando o >>operador ou passando o fileargumento para printfuncionar no Python3. Portanto, sys.stdouté apenas um valor padrão que pode ser substituído.
warvariuc