2013-02-13 2 views
0

В моей работе мы используем архитектуру CQRS с доменом Driven для нашей программной платформы с системой хранения событий, чтобы мы могли перезагрузить события в домене, в случае изменений домена в новые релизы. Пока ничего особенного.Хранилища событий, домены и гибкость, как обращаться

Одно из наших рабочих соглашений заключается в том, что мы стараемся избегать изменения событий любой ценой, поскольку это нарушает более старые версии событий в хранилище событий в рабочей среде. Если мы действительно хотим изменить событие, мы должны написать конвертеры для старых версий, и поскольку это может стать утомительным, запутанным, а иногда даже невозможным, мы стараемся избегать этого как можно больше.

Однако мы также разрабатываем программное обеспечение Agile, что означает для меня (помимо всего прочего) «не планируйте слишком много в своем коде и только пишете код, который вы собираетесь использовать в ближайшем будущем ». Это имеет смысл для меня в большинстве случаев.

Но это становится проблемой с вышеупомянутыми событиями. Когда я создаю новые события, я должен добавить к ним почти все соответствующие данные, чтобы любая система, которая когда-либо обрабатывала событие, имела все необходимые ему данные. Однако, с точки зрения Agile, я бы предпочел только добавлять данные к событиям, которые мне действительно нужны в этот момент времени.

Так что мои вопросы; Каков наилучший способ справиться с этой дилеммой? Единственные «решения», о которых я мог подумать, - это либо отказаться от правила редактирования без событий, либо просто принять, что нам придется писать преобразователи событий или пытаться добавить как можно больше релевантных данных для каждого события и создавать новые события, если в будущем данных еще недостаточно.

Другая возможность заключается в том, что в нашем способе мышления просто есть недостаток. Что вы считаете самым слабым звеном в этом подходе? Есть ли лучшие способы справиться с этим?

Я надеюсь, что этот вопрос имеет смысл, и я с нетерпением жду других точек зрения :)

+0

Какие поля имеют у вас событий? И в каких областях вы часто меняетесь? –

+0

Я голосую, чтобы закрыть этот вопрос как не относящийся к теме, потому что [управление проектами теперь не в тему по переполнению стека] (// meta.stackoverflow.com/questions/343829/is-stack-overflow-an-appro-website -в-аск-о-проект-менеджмент-вопросы/343841 # 343841). Задайте эти вопросы на [SoftwareEngineering.SE] (// softwareengineering.stackexchange.com/) и [ProjectManagement.SE] (// pm.stackexchange.com/). (Вы также можете отметить вмешательство модератора, чтобы этот вопрос был перенесен.) – robinCTS

ответ

1

Объект домена не может угадать потребности любого абонента. Обязанность объекта домена - только генерировать событие, говорящее о том, что произошло. по @MikeSW в этом answer

Вот мои стратегии:

а) Опубликовать события с основными полями с помощью компонентов запросов.

Например, мы работаем над заявлением о комментариях отеля.Каждый комментарий может быть просмотрен только другими клиентами после утверждения администратором.

public class CommentApprovedEvent { 
    private String commentId; 
} 

И обработчик события обновляет статус данных запроса комментария. Это так хорошо. Иногда позже следуют некоторые дополнительные требования, например, когда одобряется комиссия, последний одобренный комментарий должен рассматриваться как «рекомендуемый» комментарий отеля.

У нас есть hotelId и содержание в комментарии. Но на этот раз мы решили не добавлять их к событию. Вместо этого, мы используем запрос, чтобы получить его в обработчик события:

общественного класса HotelEventHandler {

public void on(CommentApprovedEvent event) { 
     CommentDetailDto comment = commentDetailQueryService. 
      findBy(event.getCommentId()); 
     comment.getHotelId(); 
     comment.getContent(); 
     //update hotel's query data 
    } 
} 

Иногда это даже невозможно, чтобы добавить все соответствующие данные события. Например, иногда позже возникает новое требование: комментатор должен быть перезаписан с некоторыми кредитами, когда комментарий одобрен. Но у нас нет комментариев в комментарии к комментарию. Поэтому мы снова выбираем запрос.

b) Разделить большое событие на более мелкие. В этом случае мы могли бы добавлять новые события вместо новых атрибутов. Рассмотрим случай доставки в образце DDD, поставка является важным объектом значение в области грузового Wich показывает, что многие аспекты данного груза:

/** 
* The actual transportation of the cargo, as opposed to 
* the customer requirement (RouteSpecification) and the plan (Itinerary). 
* 
*/ 
public class Delivery {//value object 

    private TransportStatus transportStatus; 
    private Location lastKnownLocation; 
    private Voyage currentVoyage; 
    private boolean misdirected; 
    private Date eta; 
    private HandlingActivity nextExpectedActivity; 
    private boolean isUnloadedAtDestination; 
    private RoutingStatus routingStatus; 
    private Date calculatedAt; 
    private HandlingEvent lastEvent; 
    .....rich behavior omitted 
} 

Поставка указывает на текущее состояние груза, она пересчитывается один раз новый обработка событий груза регистрируется или спецификация маршрут меняется:

//non-cqrs style of cargo 
public void specifyNewRoute(final RouteSpecification routeSpecification) { 
    this.routeSpecification = routeSpecification; 
    // Handling consistency within the Cargo aggregate synchronously 
    this.delivery = delivery.updateOnRouting(this.routeSpecification, this.itinerary); 
} 

Это пришло мне в голову, что мне нужна CargoDeliveryUpdatedEvent на первый, как:

//cqrs style of cargo 
public void deriveDeliveryProgress(final HandlingHistory handlingHistory) { 
    apply(new CargoDeliveryUpdatedEvent(
     this.trackingId, delivery.derivedFrom(routeSpecification(), 
     itinerary(), handlingHistory); 
} 

class CargoDeliveryUpdatedEvent { 
    private String trackingId; 
    private ..... //same fields in Delivery? 
    private ..... //add more when requirements evolves? 
} 

Но в конце концов я обнаружил, что я мог бы использовать меньшие события, которые могли бы выявить намерения лучше, как:

//cqrs style of cargo 
public void deriveDeliveryProgress(final HandlingHistory handlingHistory) { 
    final Delivery delivery = Delivery.derivedFrom(
     routeSpecification(), itinerary(), handlingHistory); 
    apply(new CargoRoutingStatusRecalculatedEvent(this.trackingId, 
     delivery.routingStatus()); 
    apply(new CargoTransportStatusRecalculatedEvent(this.trackingId, 
     delivery.routingStatus()); 
    ....sends events telling other aspects of the cargo 
} 

class CargoRoutingStatusRecalculatedEvent{ 
    private String trackingId; 
    private String routingStatus; 
} 

class CargoTransportStatusRecalculatedEvent{ 
    private String trackingId; 
    private String transportStatus; 
} 

Надежда это помогает. Приветствия.

0

Как долго вы хранящие события для? Является ли ваша проблема только в течение коротких периодов работы «смешанного режима» во время обновления системы или у вас есть своего рода модель длительного хранения, которая требует поддержки нескольких исторических версий событий?

+0

Мы сохраняем каждое событие неопределенно. Идея состоит в том, что мы можем полностью перестроить домен, если логика домена когда-либо изменится. – Dennisch

+0

В этом случае у вас есть проблема: семантика вашего домена будет меняться со временем, и каждая версия события должна быть связана с определенной семантикой, существовавшей в домене во время создания события. Это очень похоже на классические проблемы, связанные с версиями API. – Addys

+0

Другими словами, повторение потока событий против версии N вашего домена, скорее всего, не приведет к тому же конечному состоянию, что и воспроизведение одного и того же потока с версией N + 1, поскольку бизнес-логика, которая обрабатывает эти события, может измениться. – Addys

0

«Изменения» должны быть приняты, а не предотвращены. Ваша система должна иметь встроенное решение для принятия изменений в рамках обычного жизненного цикла программного обеспечения. Против этого может «стоить» вам больше, чем внедрять решение, принимающее его как «особенность».

Я бы пошел в том же направлении, что и Адди, если бы правильно понял его. Вам нужно обновить свою модель событий. Вы должны создать добрую версию/систему программного обеспечения, которая позволила бы любой новой версии программного обеспечения быть обратно совместимой с более старой моделью событий. Я не думаю, что это непреодолимая проблема, но вам, возможно, придется вернуться к вашим архитектурным чертежам.