グローバルリクエストコンテキスト-アンチパターン?


12

今日、私の同僚とPython Webフレームワークとそれらについての印象について話していました。私は、Flaskがグローバルなリクエストを持っているのはひどく臭いで、アンチパターンだと彼に言った。

ドキュメントは、要求コンテキストについて言います:

対照的に、リクエストの処理中には、他にもいくつかのルールがあります。

  • 要求がアクティブな間、コンテキストローカルオブジェクト(flask.requestなど)は現在の要求を指します。
  • コードはいつでもこれらのオブジェクトを保持できます。

アプリケーションをよりシンプルにするという、この設計決定の背後にある考え方を理解していると思います。Thread Localsの場合のように、これは単なる妥協です。

はい、通常、スレッドローカルを使用することはそれほど賢明な考えではありません。これらは、スレッドの概念に基づいていないサーバーに問題を引き起こし、大規模なアプリケーションの保守を困難にします。ただし、Flaskは大規模なアプリケーションや非同期サーバー向けに設計されたものではありません。Flaskは、従来のWebアプリケーションをすばやく簡単に記述できるようにしたいと考えています。

グローバルオブジェクトに現在の要求情報をパッチすることはアンチパターンですか?

静的コードアナライザーの観点ではグローバルステートであるため、そうではないと考えています。そして、プログラマーとしての私は、ドキュメントを注意深く読むことなく、それがどのように機能するかを理解しません。そして、これはテストに結果をもたらします

ビューへの引数としてリクエストを渡すことは良い習慣ではありませんか?読みやすく、明示的で、デバッグが簡単だと思います。そして、グローバルな状態を回避します。


2
このようなアンチパターンの特定のマイナス効果が何であるかについては、実際には述べていません。私は事実に基づかない抜本的な一般性を信じません。
ロバートハーヴェイ14年

2
良い質問ですが、残念ながら質の高い回答は多くありません
-sleepycal

回答:


4

多くのWebフレームワークには、同じ構造、つまりグローバルリクエストがあります。ある意味では、それは正しいことです。なぜなら、実際には一度に1つの要求しかないからです。

それでは、リクエストをパラメーターとして渡すことに何かポイントがありますか?いいえ。リクエストはリクエストであり、パラメータは異なる時間に異なるものを渡すためのものです。

本当のあなたは大規模アプリケーションの下位レベルを検討し始めとして、問題が来ます。グローバルリクエストでは、リクエストにグローバルにアクセスする場所全体にコードを記述したくなる誘惑があります。それは非常に悪いことです。コードの異なる部分間の結合を生成し、物事を変更することを困難にし、物事をテストすることを困難にします。

だから私の答えは、グローバルなリクエストを維持し、それと共に生き続けることです。ただし、個々のモジュールまたは関数が要求全体を必要としない場合は、必要なデータのみをパラメーターとして渡します。リファラー、URL、またはコマンドテールと必要なビットを関数に渡すだけです。これにより、コードをモジュール化して、結合を減らし、テスト容易性を向上させることができます。

小さなプログラムの場合、それはほとんど問題になりませんが、大きなプログラムの場合、これは実際の命の恩人になります。


3

(私は大胆になり、これを答えにしますが、いくつかのダウン票を得るかもしれません。)

フラスコはマイクロフレームワークです。フリルをあきらめながら、シンプルさの恩恵を受けます。腸のレベルではあなたに同意しますが、あるショップでフラスコ+ gunicornを使用して、必要なマルチスレッドを提供していることは知っています。それは働いた本当にうまく。スクリプトの各インスタンスは1つのリクエスト(つまり1つのスレッド)を渡すだけで、gunicornは複数のスレッド間で「ファンアウト」を処理しました。それは素晴らしかったです。

したがって、複数のスレッドがグローバルステートをめぐって競合する可能性があると感じているマイナス面は、スレッドごとに1つのスクリプトであるため、問題ではありません。

(ここで問題が発生する可能性があります)スレッド化と同時実行性はPythonの世界ではまったく異なります。Javaのフレームワークでそれを実現するのは困難です。私が経験した同時性の問題Javaで付与されたもの、またはアプリケーションコンテナによって透過的に処理されるものは、Pythonの表面にずっと近いものです。

1つのスレッドがスクリプトの1つの呼び出しを処理することは私にとっては奇妙でしたが、同時に数十個のボックスで実行された後、私はそれについて気分が良くなりました。


4
スレッドの安全性などは心配していません。Flaskはこれらの場合にうまく機能すると思います。私の質問は、アプリケーションの設計とアーキテクチャに関するものです。ビューへの引数としてリクエストを渡すことは良い習慣ではありませんか?読みやすく、明示的で、デバッグが簡単だと思います。
warvariuc 14年

2

Pythonにはprint、標準出力に出力するコマンド(v3以降の関数)があります。STDOUTに印刷することを明示的に指定することはありません。暗黙的に背後で行われます。

暗黙的に。Pythonで。誰も問題はありません。どうして?

printはPython言語の一部であり、Pythonでのプログラミングの要件の1つは...ええと... Pythonを知っていることです。Pythonを知っていれば、それがprintSTDOUT をターゲットにしていることを知っています。驚きはありません。

Pythonは、言語として、独自の規則を定義し、プログラマーがそれらを認識していると想定できます。

フレームワークもその特権を享受します。これは、フレームワークとライブラリの重要な違いの1つです。ライブラリを使用するために学習する必要はありません。必要なAPIの部分を見つけ、それが言語(またはフレームワーク)の規則に従っていると仮定するだけです。そのため、GSONやApache Commonsの知識を持つ人材を探している採用担当者がいません。しかし、JQuery、Ruby on Rails、またはASP.NET MVCの経験を持つ人材を探している採用担当者がいます。これらは、学習して認識しなければならない独自の規則を定義するフレームワークであるためです。

フレームワークとしてのFlaskは、コンテキストをスレッドローカルグローバルに格納するための規則を定義できます。また、誰も驚かないはずであるため、アンチパターンではありません。


2
「stdout」は、が指すファイル記述子を意味することに注意してくださいsys.stdout。これを変更すると、印刷は別の場所に移動します。
Phoshi

1
また、>>演算子を使用するか、Python3の関数にfile引数を渡すことにより、出力ストリームをオーバーライドできますprint。したがって、sys.stdoutオーバーライドできる単なるデフォルト値です。
warvariuc 14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.