Contesto di richiesta globale - anti-pattern?


12

Oggi stavo parlando con un mio collega dei framework Web Python e delle nostre impressioni su di essi. Gli ho detto che penso che Flask abbia una richiesta globale ha un cattivo odore ed è un anti-schema.

I documenti dicono sul contesto della richiesta:

Al contrario, durante la gestione delle richieste, esistono un paio di altre regole:

  • mentre una richiesta è attiva, gli oggetti locali di contesto (flask.request e altri) puntano alla richiesta corrente.
  • qualsiasi codice può ottenere questi oggetti in qualsiasi momento.

Penso di aver compreso l'idea alla base di questa decisione di progettazione: rendere l'applicazione più semplice. È solo un compromesso, come nel caso dei locali dei thread :

Sì, di solito non è un'idea così brillante usare i locali dei thread. Causano problemi per i server che non si basano sul concetto di thread e rendono più difficile la gestione di grandi applicazioni. Tuttavia Flask non è progettato per applicazioni di grandi dimensioni o server asincroni. Flask vuole rendere semplice e veloce la scrittura di un'applicazione web tradizionale.

Patching di un oggetto globale con le informazioni della richiesta corrente è un anti-pattern?

Credo che lo sia, perché secondo l'analizzatore di codice statico è uno stato globale, sebbene non lo sia. E come programmatore non capirò come funziona senza leggere attentamente i documenti . E questo ha conseguenze sui test .

Non è una buona pratica passare la richiesta come argomento alle viste? Penso che sia più leggibile, esplicito e più facile da eseguire il debug. Ed evita lo stato globale.


2
Non hai davvero dichiarato quali potrebbero essere gli effetti negativi specifici di un simile antipasto. Diffido delle generalità generali che non hanno basi fattuali.
Robert Harvey,

2
Bella

Risposte:


4

Molti framework Web hanno la stessa struttura: una richiesta globale. In un certo senso, è la cosa giusta da fare perché, ehi, c'è davvero solo una richiesta alla volta.

Quindi ha senso passare la richiesta come parametro? No. La richiesta è la richiesta e i parametri sono per passare in cose diverse in momenti diversi.

Il vero problema arriva quando inizi a considerare i livelli più bassi di un'applicazione più grande. Con una richiesta globale c'è la tentazione di scrivere codice in tutto il luogo che accede alla richiesta a livello globale. Questa è una brutta cosa . Produce accoppiamento tra le diverse parti del codice, rende difficile cambiare le cose e rende difficile testare le cose.

Quindi la mia risposta è: mantenere la richiesta globale e convivere con essa. Tuttavia, ovunque un singolo modulo o funzione non necessiti dell'intera richiesta, passa solo i dati di cui ha bisogno come parametro. Passa solo il referrer, o l'url o la coda dei comandi e qualsiasi bit di cui hai bisogno nelle tue funzioni. Ciò contribuirà a mantenere il codice modulare, ridurre l'accoppiamento e migliorare la testabilità.

Per i programmi di piccole dimensioni poco importa, ma per quelli più grandi può essere un vero toccasana.


3

(Sto andando in grassetto e farò una risposta, anche se potrei ottenere alcuni voti negativi.)

Flask è un micro-quadro; beneficiate della semplicità mentre rinunciate ai fronzoli. Mentre a livello intestinale sono d'accordo con te, so che ho usato fiaschetta + gunicorn in un negozio per darmi il multi-threading di cui avevo bisogno. Ha funzionato davvero bene. Ogni istanza dello script ha appena consegnato una richiesta (ovvero un thread) e gunicorn ha gestito il "fan out" tra più thread. È stato fantastico.

Quindi il lato negativo percepito che senti - che più thread potrebbero contendere lo stato globale - non è un problema, perché è uno script per thread.

(Ecco dove potrei finire nei guai) Il threading e la concorrenza sono semplicemente diversi nel mondo di Python, e se ci si arriva con una mentalità Java, è difficile comprimerlo. La mia esperienza è che i problemi di concorrenza che ho preso per concesso in Java o gestito in modo trasparente dal contenitore dell'applicazione, è molto più vicino alla superficie in Python.

Era strano per me che un thread gestisse una sola invocazione della mia sceneggiatura, ma dopo aver fatto girare una dozzina contemporaneamente su una scatola, mi sentivo meglio.


4
Non sono preoccupato per la sicurezza del thread e simili. Credo che Flask funzioni bene in questi casi. La mia domanda riguarda la progettazione e l'architettura delle applicazioni. Non è una buona pratica passare la richiesta come argomento alle viste? Penso che sia più leggibile, esplicito e più facile da eseguire il debug.
Warvariuc,

2

In Python hai il printcomando (funzione dalla v3) che stampa sull'output standard. Non specifichi esplicitamente di voler stampare su STDOUT: è fatto per te implicitamente dietro le quinte.

Implicitamente. In Python. E nessuno ha problemi con questo. Perché?

printfa parte del linguaggio Python e un requisito di programmazione in Python è ... beh ... conoscere Python. E se conosci Python, sai che ha come printtarget STDOUT. Nessuna sorpresa lì.

Python - come linguaggio - può definire la propria convenzione e presumere che i programmatori ne siano consapevoli.

Anche i framework godono di quel privilegio: questa è una delle differenze chiave tra un framework e una libreria. Non devi imparare una libreria per usarla - devi solo trovare la parte dell'API di cui hai bisogno e assumere che segua le convenzioni della lingua (o del framework). Ecco perché non vedi reclutatori che cercano persone con conoscenze in GSON o Apache Commons. Ma vedi reclutatori che cercano persone con esperienza con JQuery o Ruby on Rails o ASP.NET MVC - perché quelli sono quadri che definiscono le proprie convenzioni che devi imparare e conoscere.

Flask, come framework, può definire una convenzione per la memorizzazione del contesto in un globale locale thread - e non dovrebbe sorprendere nessuno, quindi non è un anti-pattern.


2
Si noti che "stdout" indica qualsiasi descrittore di file indicato da sys.stdout. Se lo cambi, la stampa va altrove.
Phoshi,

1
Inoltre, puoi sovrascrivere il flusso di output usando l' >>operatore o passando l' fileargomento per printfunzionare in Python3. Quindi, sys.stdoutè solo un valore predefinito che può essere ignorato.
Warvariuc,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.