web-dev-qa-db-ja.com

保守可能なイベント駆動型コードの記述

私は最近、かなり標準的なオブジェクト指向の考え方から来た、イベント駆動型アーキテクチャで遊び始めました。

私が最初に気付いたのは、プログラムの理解と追跡の難しさが、プログラムのサイズとともに指数関数的に増加するように見えることでした。小さなペットのプロジェクトは簡単にたどることができますが、コードが急速にスパゲッティに変わるように感じます。

私はこの開発の考え方に慣れておらず、オブジェクト指向の心配のすべてが引き継がれるわけではないことを理解しています。保守可能で理解しやすいイベント駆動型コードの記述に関するリソースはありますか? node.js、Twisted、またはEvent Machineを使用する人々はこれについて何をしますか?

49
Mantas Vidutis

例としてPythonを使用します。これは、現在、巨大な分散アプリケーションを構築するために使用しているものです。

Twisted pythonは、インラインコールバックまたは(少し醜い)deferredGeneratorスタイルのいずれかを使用する非常に命令的なスタイルを可能にします。これらのメソッドを使用すると、読み取りと理解がはるかに簡単なイベント駆動型コールバックコードを使用するプロシージャを記述できます。実装は、関数を遅延シーケンスに変換し、遅延シーケンスを生成します。

具体的には、コールバック関数/ラムダ/クロージャの深くネストされたセットを構築する必要はなく、代わりに任意のポイントでイベントループに関数の制御を戻すことができます。必要に応じて、これをコルーチンまたは協調マルチタスクとして精神的に再ラベル付けできます。それは仕事を成し遂げます。例は次のようになります(醜いdeferredGeneratorスタイルを使用):

@defer.deferredGenerator
def foo(arg):
    bar = nonBlockingFunction(foo)
    baz = waitForDeferred(aFunctionThatReturnsADeferredToo(bar))
    yield baz #Returns control to the event loop
    output = baz.getResult() #This gets the output of aFunctionThat...Too above
    yield output #This is how we return a result instead of using return

@defer.deferredGenerator
def aFunctionThatReturnsADeferredToo(put_bar_here):
    """Stuff happens here...."""
    ...etc...

InlineCallbacksメソッドを示す別の投稿があります。これはよりクリーンですが、python 2.5以降が必要です(つまり、Centos/RHEL 5シリーズではなく、残念ながら私のアプリで立ち往生しています) 。使用できる場合はそうしてください。

ご覧のとおり、これは古い学校のように見えますpythonあなたが知っていて大好きな命令型のものですが、ネストされた関数やラムダがたくさんなくても保守がはるかに簡単です。それでもpythonにはブロックがありました。

デバッグに関しては、初期化コードのどこかでdefer.setDebugging(True)呼び出しを使用して、ツイストリアクターデバッグをオンにすることができます。これにより、コードで例外を発生させた元のトレースバックが添付されるため、エラーが実際に発生した場所を簡単に確認できます。本番環境に移行する前に、setDebuggingステートメントを編集することを忘れないでください。これは、膨大な量の余分な内省をもたらすためです(完全に恐ろしい場合は、straceで確認してください)。

4
Enki

私は このトピックに関する話 昨年Yahooでやった。

7
sh1mmer

Martyn Loughranが優れた短い記事を書きました コールバックスパゲッティの回避について完全に。

彼の記事で私が本当に楽しんだのは、スパゲッティを素敵できれいなものに改善するプロセスです。最初は少し形式化されているように見えるかもしれませんが、最終結果を見ると、彼がクリーンで読みやすいコードで本物の芸術性を示していることに同意すると思います。

6
sarnold
6
yojimbo87

Twistedの場合、古いdeferredGeneratorを使用する代わりに、inlineCallbacksをお勧めします。これにより、ブロッキングスタイルのコードを完全に記述しながら、イベントループをうまく処理できます。

@defer.inlineCallbacks
def foo(arg):
    bar = nonBlockingFunction(foo)
    output = yield FunctionThatReturnsADeferredToo(bar)
    defer.returnValue(output) #This is how we return a result instead of using return
4
jrydberg

明らかに、時間の経過とともに開発を続けるベストプラクティスとモデルがすでに存在します。

ただし、イベントプログラミングが「小さなペットプロジェクト」が相互作用する機会を提供する可能性も考慮してください。何千もの分散した個々のプロジェクトがユーザー定義のコールバックを介してリアルタイムで相互作用する世界を想像してみてください。

ユーザーと開発者は、既存のアプリケーション設計に依存する代わりに、既存のプロトコルを介してWebとアプリケーションをトップダウンで再配線できます。これにより、アプリケーション設計者は、万能のソリューションを提供したり、起こりうるあらゆる不測の事態を心配したりする代わりに、個々のユースケースに自由に集中できます。

Web Hooks をチェックして、 Twilio のようなサービスがすでにどのように動作しているかを確認してください

1
danielsiders

私の唯一のアドバイスは機能的だと思うです。

1
masylum