2017-02-09 3 views
0

Ich experimentiere mit Event Sourcing mit Scala (ich bin neu in beiden Bereichen).Event Sourcing mit Scala und unveränderlichen Objekten: Ist es effizient?

Ich möchte alles so unveränderlich wie möglich halten, einschließlich der Aggregatwurzeln. Als Basis folge ich Greg Youngs Beispiel von ES und CQRS (https://github.com/gregoryyoung/m-r, implementiert in C#) und "übersetze" diesen Code in Scala.

Frage ist über das Objekt Regeneration von Ereignisspeichern:

Da mein Aggregat Wurzeln für jedes Ereignis von bestimmten Entität unveränderlich ist, neues Objekt erstellt wird. Um beispielsweise eine Entität mit 100 Ereignissen neu zu generieren, sollten 100 Instanzen dieser Entität erstellt werden und die letzte Instanz wird der Endstatus sein.

Ist es effizient oder zu viel Aufwand?

(Ich denke max Ereignisse zu regenerieren wird 100 sein, da ich Snapshots speichern werde).

Hier ist mein Code:

Ereignis Merkmal

trait Event { 

} 

Basisklasse für Aggregate

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 
    ... 
} 

Produkt Aggregate

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

Jede Antwort hier wird zu allgemein und breit sein. Wie immer, benchmarken Sie Ihren Code, um zu sehen, ob der Aufwand zu hoch ist. Wenn dies der Fall ist, suchen Sie die Hotpfade und versuchen Sie, die Zuweisungen möglichst zu minimieren. –

Antwort

1

Nun ... wenn Sie über Effizienz sprechen, wird es immer um die Wahl Ihrer Datenstrukturen gehen und wie - was optimieren Sie?

In diesem speziellen Fall Ihre Product wie diese,

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

Und wie Sie Ihre Veranstaltungen in changes akkumulieren sucht, wird Ihre Effizienz hier durch die Datenstruktur bestimmt werden. Sie können es nicht einfach mit einem allgemeinen Seq verlassen.

Jetzt gibt es die wichtige Frage, die Sie stellen sollten - was sind Ihre Anwendungsfälle für diese changes?

Nun ... andere als alle nicht bekannten Dinge ... Ich kann sehen, dass, wenn Sie eine neue Veranstaltung erhalten, Sie es zu Ihrem changes hinzufügen möchten. Was bedeutet, dass häufige Ereignisse variieren, wenn Sie empfangen haben, als Sie den Betrieb optimieren müssen, um es hinzuzufügen, um Ihre changes

Also ... können Sie sagen changes: List[Event] verwendet haben,

Nun werden Sie prepend verwenden müssen das ist konstante Zeit - C anstelle von append was O (n) ist.

// 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 

Aber jetzt Sie changes Liste werden die Ereignisse in der umgekehrten Reihenfolge enthalten ...Sie müssen also bedenken, dass Sie diese beim Wiederherstellen des Status in umgekehrter Reihenfolge anwenden. http://docs.scala-lang.org/overviews/collections/performance-characteristics.html

nur daran erinnern, dass „Effizienz“ auf seine auf es keinen Sinn hat -

Um mehr über die Zeit-Komplexität einiger Operationen auf verschiedenen Sammlungen zu kennen, können Sie einen Blick auf diese nehmen. Du solltest immer fragen - "Effizienz ... aber was tun?"

+0

Hier Änderungen: Seq [Event] - sind tatsächlich nicht festgeschriebene Änderungen, aber nicht alle Änderungen, die im Ereignisspeicher dieser Entität gespeichert sind. Ja, Sie haben Recht mit List, danke. – Teimuraz

Verwandte Themen