イベント駆動型プログラミング:いつ価値があるのか​​?


19

わかりました、この質問のタイトルは、イベントベースのプログラミングをいつ使用する必要があるかとほぼ同じです。しかし、上記の質問の答えは、私が直面している特定のケースでイベントを使用すべきかどうかを決定するのに役立ちませんでした。

私は小さなアプリケーションを開発しています。それはシンプルなアプリであり、その機能の大部分は基本的なCRUDです。

特定のイベント(特定のデータを変更する場合)で、アプリケーションはそのデータのローカルコピーをファイルに書き込む必要があります。これを実装する最善の方法についてはわかりません。できます:

  • データが変更されたときにイベントを起動し、そのようなイベントに応答をバインド(ファイルを生成)します。または、オブザーバーパターンを実装します。それは不必要な複雑さのようです。
  • データを変更するコードからファイル生成コードを直接呼び出します。はるかに単純ですが、依存関係をこのように設定するのは間違っているようです。つまり、アプリのコア機能(データを変更するコード)をその追加の特典(バックアップファイルを生成するコード)に結合するのは間違っているようです。ただし、このアプリは、そのカップリングが問題を引き起こすポイントまで進化しないことを知っています。

この場合の最善のアプローチは何ですか?


2
自分では何も実装しないでください。既存のイベントバスを使用するだけです。これは...人生ははるかに簡単になります
ボリス・スパイダー

イベント駆動プログラミングは本質的に非同期です。イベントは、意図した順序で、または別の順序で、またはまったく行われない場合があります。その余分な複雑さに対処できるなら、それを選んでください。
ピーターB

通常、イベント駆動型とは、コードがコールバックとして提供され、予測できない方法で他の場所から呼び出されることを意味します。あなたの説明は、コードで特定の何かが発生したとき、素朴な実装が必要とする以上のことをする必要があるようです。余分な呼び出しをコーディングするだけです。
ThorbjørnRavn Andersen

そこイベント駆動型とイベントベースの違いは。たとえば、非常に刺激的な.NET Rocksポッドキャストエピソード355とTed Faisonをご覧ください。TedFaisonはイベントを限界まで引き上げます!直接ダウンロードURL)および書籍イベントベースのプログラミング:イベントを制限まで取得する
ピーターモーテンセン

Ted Faisonとのインタビューは、13分10秒から始まります。
ピーターモーテンセン

回答:


31

KISSの原則:Keep It Simple、愚かさ、またはYAGNIの原則:あなたはそれを必要としません。

次のようなコードを書くことができます。

void updateSpecialData() {
    // do the update.
    backupData();
}

または、次のようなコードを書くことができます。

void updateSpecialData() {
     // do the update.
     emit SpecialDataUpdated();
}

void SpecialDataUpdatedHandler() {
     backupData();
}

void configureEventHandlers() {
     connect(SpecialDataUpdate, SpecialDataUpdatedHandler);
}

別の方法でやるに足る理由がない場合は、より単純なルートに従ってください。イベント処理などの手法は強力ですが、コードの複雑さが増します。動作するにはより多くのコードが必要であり、コード内で発生することを追跡しにくくします。

適切な状況ではイベントは非常に重要です(イベントなしでUIプログラミングを試みることを想像してください!)。しかし、代わりにKISSまたはYAGNIできる場合は使用しないでください。


特に、データが変更されたときにイベントを発生させるのは簡単ではないというおっしゃった事実が気に入っています。
-NoChance

13

変更が何らかの効果を引き起こす単純なデータの例は、オブザーバーデザインパターンで完全に実装できます

  • これは、完全なイベント駆動型コードよりも実装および保守が簡単です。
  • サブジェクトとオブザーバーの結合は抽象的である場合があり、懸念の分離を促進します。
  • 1対多の関係に最適です(被験者には1人以上のオブザーバーがいます)。

イベント駆動型アプローチは、多対多のコンテキストで多くの異なる相互作用が発生する可能性がある場合、または連鎖反応が想定される場合(たとえば、サブジェクトがオブザーバーに通知し、場合によっては主題または他の主題)


1
私は混乱しています、オブザーバーはイベントを実装する唯一の方法ではありませんか?
svick

1
@svickそうは思いません。でイベント駆動型プログラミングあなたは切り離さ送信者とオブザーバーとの多くの関係に多くの主要なループそのプロセスのイベントを、持っています。オブザーバーは、特定の種類のイベントを処理することで貢献できると思いますが、オブザーバーだけではEDPの全範囲を達成することはできません。私は混乱がイベント駆動型ソフトウェアでは、オブザーバーは時々 (GUIで一般的にMVC)イベント処理の上に実装されているという事実から来ていると思います
クリストフ・

5

あなたが言うように、イベントはクラス間の結合を減らす素晴らしいツールです。そのため、イベントの組み込みサポートなしで一部の言語で追加のコードを記述することができますが、全体像の複雑さは軽減されます。

イベントは間違いなくオブジェクト指向の最も重要なツールの1つです(Alan Kayによれば、オブジェクトはメッセージを送受信することで通信します)。イベントの組み込みサポートを備えた言語を使用する場合、または関数をファーストクラスの市民として扱う場合、それらを使用するのは簡単です。

サポートが組み込まれていない言語でさえ、Observerパターンのようなものの定型的な量はごくわずかです。すべてのアプリケーションで使用できるまともな汎用イベントライブラリをどこかで見つけて、ボイラープレートを最小限に抑えることができます。(汎用イベントアグリゲーターまたはイベントメディエーターは、ほとんどすべての種類のアプリケーションで役立ちます)。

小さなアプリケーションでは価値がありますか?私は間違いなくイエスと言うでしょう。

  • クラスを相互に分離しておくと、クラスの依存関係グラフがきれいに保たれます。
  • 具体的な依存関係のないクラスは、テスト内の他のクラスを考慮することなく、単独でテストできます。
  • 具体的な依存関係のないクラスでは、完全なカバレッジを得るために必要な単体テストが少なくなります。

あなたにしている考え方は、場合、「それは本当にごく小さなアプリケーションですが、それは本当にそれほど重要ではありませんああけど」、考慮してください。

  • 小さなアプリケーションは、後に大きなアプリケーションと組み合わされることがあります。
  • 小規模なアプリケーションには、少なくとも他のアプリケーションで後で再利用する必要のあるロジックまたはコンポーネントが少なくとも含まれている可能性があります。
  • 小規模なアプリケーションの要件は変更される可能性があり、リファクタリングが必要になります。これは、既存のコードを切り離すと容易になります。
  • 後で追加機能を追加して、既存のコードを拡張する必要性を促すことができます。これは、既存のコードが既に分離されている場合もはるかに簡単です。
  • 疎結合コードは一般に、密結合コードよりも書くのにそれほど時間はかかりません。ただし、密結合コードは、疎結合コードよりもリファクタリングとテストに時間がかかります。

全体として、アプリケーションのサイズは、クラスを疎結合に保つかどうかを決定する要因ではありません。SOLIDの原則は、大規模なアプリケーションだけでなく、あらゆる規模のソフトウェアとコードベースに適用できます。

実際、疎結合クラスを単体でテストするユニットで節約される時間は、それらのクラスの分離に費やされる追加の時間と釣り合うはずです。


2

オブザーバーパターンは、プログラミング言語が「コールバック」や「デリゲート」などをサポートしていると仮定して、Wikipediaの記事(またはGOFの本)で説明されているよりもはるかに小さい方法で実装できます。コールバックメソッドをCRUDコードに渡すだけです(オブザーバーメソッド。汎用の「ファイルへの書き込み」メソッドまたは空のメソッドのいずれかです)。「イベント発生」の代わりに、そのコールバックを呼び出すだけです。

結果として生成されるコードは、ファイル生成コードを直接呼び出すよりも複雑ですが、無関係なコンポーネントが密結合するという欠点はありません。

これにより、「YAGNI」のデカップリングを犠牲にすることなく、「両方の長所」を実現できます。


これは初めてのDocで機能しますが、イベントが2番目のトリガーをトリガーする必要がある場合、この方法でクラスを変更する必要がある可能性があります。オブザーバーパターンを使用する場合は、元のクラスを開いて変更することなく、必要なだけ新しい動作を追加できます。
ラバーダック

2
@RubberDuck:OPは「不要な複雑さを回避する」ソリューションを探していました-異なるイベント/異なる動作が必要な場合、おそらく彼はオブザーバーパターンを複雑すぎるとは思わないでしょう。それで、あなたが言ったことに同意します、物事がより複雑になるとき、完全なオブザーバーは彼にもっと役立つでしょうが、その時だけです。
ドックブラウン

公平な声明ですが、私には壊れた窓のように感じます。
ラバーダック

2
@RubberDuck:完全にオブザーバーを追加し、パブリッシャー/サブスクライバーの仕組みを「念のために」、実際には必要でない場合、オーバーエンジニアリングのように感じます-それは良くありません。
ドックブラウン

1
私はそれがエンジニアリングを超えている可能性があることに同意しません。私が選んだスタックに実装するのは簡単だから、おそらく自分のやり方を感じるでしょう。とにかく、私たちは同意しないことに同意しますか?
ラバーダック
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.