2017-02-09 7 views
0

Я экспериментирую с Event Sourcing с Scala (я новичок и в этих двух областях).Event Sourcing с Scala и неизменяемыми объектами: эффективен ли он?

Я хотел бы сохранить все как можно более неизменными, включая совокупные корни. В качестве базы я следую примеру Грега Янга ES и CQRS (https://github.com/gregoryyoung/m-r, реализованному на C#) и «перевод» этого кода в Scala.

Вопрос о регенерации объекта из хранилища событий:

Поскольку мои агрегатные корни неизменны, для каждого события конкретного объекта, новый объект создается. Так, например, для восстановления объекта, который имеет 100 событий, 100 экземпляров этого объекта должны быть созданы, а последний экземпляр будет конечным.

Является ли это эффективным или слишком накладным?

(Я думаю, что максимальное количество событий для восстановления будет 100, так как я буду хранить моментальные снимки).

Вот мой код:

черта события

trait Event { 

} 

Базовый класс для агрегатов

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

продукт Совокупный

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

Так что ... позволяет сказать, что вы использовали changes: List[Event],

Теперь, вы должны будете использовать prepend который является постоянным временем - C вместо append, который является O (n).

// 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] - это фактически незафиксированные изменения, но не все изменения, которые хранятся в хранилище событий этого объекта. Да, вы правы насчет Списка, спасибо. – Teimuraz

Смежные вопросы