Estuve hablando hoy con un colega mío sobre los marcos web de Python y nuestras impresiones sobre ellos. Le dije que creo que Flask tiene una solicitud global que huele mal y es un antipatrón.
Los documentos dicen sobre el contexto de la solicitud:
Por el contrario, durante el manejo de solicitudes, existen otras dos reglas:
- Mientras una solicitud está activa, los objetos locales de contexto (flask.request y otros) apuntan a la solicitud actual.
- cualquier código puede obtener estos objetos en cualquier momento.
Creo que entiendo la idea detrás de esta decisión de diseño: simplificar la aplicación. Es solo un compromiso, como en el caso de Thread Locals :
Sí, por lo general, no es una idea tan brillante usar hilos locales. Causan problemas para los servidores que no se basan en el concepto de subprocesos y hacen que las aplicaciones grandes sean más difíciles de mantener. Sin embargo, Flask no está diseñado para aplicaciones grandes o servidores asíncronos. Flask quiere que sea rápido y fácil escribir una aplicación web tradicional.
¿El parchear un objeto global con la información de solicitud actual es un antipatrón?
Creo que es, porque es para el analizador de código estático un estado global, aunque no lo es. Y como programador no entenderé cómo funciona sin leer los documentos detenidamente. Y esto tiene consecuencias en las pruebas .
¿No es una buena práctica pasar la solicitud como argumento a las vistas? Creo que es más legible, explícito y más fácil de depurar. Y evita el estado global.
fuente
Respuestas:
Muchos marcos web tienen esta misma estructura: una solicitud global. En cierto sentido, es lo correcto porque, oye, realmente solo hay una solicitud a la vez.
Entonces, ¿hay algún punto en pasar la solicitud como parámetro? No. La solicitud es la solicitud, y los parámetros son para pasar cosas diferentes en momentos diferentes.
El verdadero problema surge cuando comienzas a considerar niveles más bajos de una aplicación más grande. Con una solicitud global existe la tentación de escribir código en todo el lugar que accede a la solicitud de forma global. Eso es algo muy malo . Produce acoplamiento entre diferentes partes del código, dificulta cambiar las cosas y dificulta probarlas.
Entonces mi respuesta es: mantener la solicitud global y vivir con ella. Sin embargo, siempre que un módulo o función individual no necesite la solicitud completa, pase solo los datos que necesita como parámetro. Pase solo el referente, o la url, o la cola del comando y los bits que necesite en sus funciones. Esto ayudará a mantener el código modular, reducir el acoplamiento y mejorar la capacidad de prueba.
Para programas pequeños apenas importa, pero para los más grandes esto puede ser un verdadero salvavidas.
fuente
(Voy a ir en negrita y hacer de esto una respuesta, aunque podría obtener algunos votos negativos).
Flask es un micro marco; Usted se beneficia de la simplicidad mientras renuncia a los adornos. Si bien estoy en un nivel instintivo, estoy de acuerdo con usted, sé que utilicé frasco + gunicorn en una tienda para darme el subproceso múltiple que necesitaba. Funcionó muy bien. Cada instancia del guión acaba de entregar una solicitud (es decir, un hilo), y gunicorn manejó el "abanico" entre múltiples hilos. Fue genial en eso.
Entonces, el inconveniente percibido que está sintiendo, que múltiples hilos podrían competir por el estado global, simplemente no es un problema, porque es un script por hilo.
(Aquí es donde puedo meterme en problemas) El enhebrado y la concurrencia son simplemente diferentes en el mundo de Python, y si se llega a esto con un estado de ánimo de Java, es difícil exprimirlo. Mi experiencia fue que los problemas de concurrencia que tomé por otorgado en Java, o que se manejan de forma transparente por el contenedor de la aplicación, están mucho más cerca de la superficie en Python.
Me resultaba extraño que un hilo manejara una invocación de mi guión, pero después de ejecutar algunas docenas en una caja al mismo tiempo, me sentí mejor al respecto.
fuente
En Python tiene el
print
comando (función desde v3) que se imprime en la salida estándar. No especifica explícitamente que desea imprimir en STDOUT; se hace implícitamente detrás de escena.Implícitamente. En Python Y nadie tiene un problema con eso. ¿Por qué?
print
es parte del lenguaje Python, y uno de los requisitos de programación en Python es ... bueno ... conocer Python. Y si conoces Python, sabes queprint
apunta a STDOUT. No hay sorpresas allí.Python, como lenguaje, puede definir su propia convención y asumir que los programadores las conocen.
Los marcos también disfrutan de ese privilegio, esa es una de las diferencias clave entre un marco y una biblioteca. No tiene que aprender una biblioteca para usarla, solo necesita encontrar la parte de la API que necesita y asumir que sigue las convenciones del lenguaje (o marco). Es por eso que no ves reclutadores que buscan personas con conocimiento en GSON o Apache Commons. Pero sí ve reclutadores que buscan personas con experiencia con JQuery o Ruby on Rails o ASP.NET MVC, porque esos son marcos que definen sus propias convenciones que necesita aprender y conocer.
Flask, como marco, puede definir una convención para almacenar el contexto en un subproceso local global, y no debería sorprender a nadie, por lo que no es un antipatrón.
fuente
sys.stdout
. Si cambia eso, la impresión va a otra parte.>>
operador o pasando elfile
argumento paraprint
funcionar en Python3. Por lo tanto,sys.stdout
es solo un valor predeterminado que se puede anular.