2017-02-09 3 views
0

私はScalaでEvent Sourcingを試しています(私はこの2つのフィールドの両方で新しくなっています)。Scalaと不変オブジェクトによるイベントソーシング:効率的ですか?

私は可能な限り不変なものをすべて集めておきたいと思います。 ベースとして、私はESとCQRS(https://github.com/gregoryyoung/m-r、C#で実装されています)のグレッグヤングの例と、このコードをScalaに '翻訳'しています。私の集計のルーツは不変なので、特定のエンティティの各イベントのために、新しいオブジェクトが作成され

質問は、イベント・ストアからのオブジェクトの再生についてです。たとえば、100個のイベントを持つエンティティを再生成するには、このエンティティの100個のインスタンスを作成し、最後のインスタンスを最終状態にする必要があります。

オーバーヘッドが効率的かオーバーヘッドが大きいですか?

(私はスナップショットを保存するので、再生する最大イベントは100と思う)ここで

は私のコードです:集計

abstract class AggregateRoot { 

    ... 
    // HERE ENTITY IS REGENERATED FROM EVENTS AND EACH TIME NEW INSTANCE IS CREATED FOR EACH ENTITY 

    def loadFromHistory(history: Seq[Event]): AggregateRoot = { 
    var aggregate = this 
    history.foreach(e => aggregate = applyChange(e, false)) 
    aggregate 
    } 

    def applyChange(event: Event, isNew: Boolean): AggregateRoot 
    ... 
} 

製品の集計

ため

イベント特色

trait Event { 

} 

基底クラス

case class Product(id: Long, name: String, status: Int, uncommittedChanges: Seq[Event]) extends AggregateRoot { def changeName(name: String): Product = { applyChange(ProductNameChangedEvent(id = this.id, name = name)) } def applyChange(event: Event, isNew: Boolean = true): Product = { val changedProduct = event match { case e: ProductCreatedEvent => applyChange(e) case e: ProductNameChangedEvent => applyChange(e) case _ => throw new Exception("No event applier") } // ALSO HERE I'M COPING ALL THE LOCAL (NEW) CHANGES (THAT ARE NOT STORED IN EVENT STORE YET) if (isNew) changedProduct.copy(uncommittedChanges = uncommittedChanges :+ event) else changedProduct } def applyChange(event: ProductCreatedEvent): Product = { this.copy(id = event.id, name = event.name) } def applyChange(event: ProductNameChangedEvent): Product = { this.copy(id = event.id, name = event.name) } ... } 
+0

ここでの回答はあまり一般的ではありません。いつものように、あなたのコードをベンチマークし、あまりにもオーバーヘッドかどうかを確認してください。そうであれば、ホットパスを見つけて、可能な限り割り当てを最小限に抑えてください。 –

答えて

1

まあ...効率について言えば、それはいつもあなたのデータ構造の選択肢に落ちて、どのように最適化していますか?あなたのProductはこのようになります。この特定のケースで

case class Product(id: Long, name: String, status: Int, changes: Seq[Event]) 

そして、あなたはchangesであなたのイベントを蓄積しているとして、あなたの効率は、ここでデータ構造によって決定されます。あなたは一般的なSeqでそれを残すことはできません。

ここで重要な質問があります。これはあなたのユースケースは何ですか?changes

まあ...すべての未知のもの以外のもの...新しいイベントを受け取るたびに、それをあなたのchangesに追加したいことがわかります。あなたは今changes: List[Event]

を使用していたと言うことができますどのあなたがchanges

に追加の動作を最適化ので、必要以上に頻繁にイベントを、あなたが受けている場合は異なることを意味します...、あなたはprependを使用する必要がありますこれはO(n)であるappendの代わりに一定の時間Cです。

// so this line 
if (isNew) changedProduct.copy(changes = changes :+ event) else changedProduct 

// will have to changed to 
if (isNew) changedProduct.copy(changes = event +: changes) else changedProduct 

しかし、今はchangesリストを逆の順序でイベントが含まれています...あなたの状態を再構築するときは逆の順序でそれらを適用することを覚えておく必要があります。

する様々なコレクションの一部の操作の時間複雑さについての詳細を知るためには、あなたがこれを見て取るべきである - http://docs.scala-lang.org/overviews/collections/performance-characteristics.html

だけを、その上にその上の「効率性」は意味を持たないことを覚えておいてください。あなたは常に "効率...しかし何をするか?"と尋ねるべきです。

+0

変更点:Seq [Event] - 実際にコミットされていない変更ですが、このエンティティのイベントストアに格納されている変更はすべてありません。はい、ありがとうございます。List、ありがとうございます。 – Teimuraz

関連する問題