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.
fonte
Respostas:
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.
fonte
(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.
fonte
No Python, você tem o
print
comando (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ê?
print
faz parte da linguagem Python, e um requisito de programação em Python é ... bem ... conhecer Python. E se você conhece Python, sabe queprint
tem 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.
fonte
sys.stdout
. Se você mudar isso, a impressão vai para outro lugar.>>
operador ou passando ofile
argumento paraprint
funcionar no Python3. Portanto,sys.stdout
é apenas um valor padrão que pode ser substituído.