Каждая служба может иметь внутреннюю модель, и вы можете использовать Каноническую модель данных для связи между службами.
Обычно для интеграции используется отдельная модель, которая используется внутренней модель, которую использует служба.
Вы также можете проверить все шаблоны в enterpriseintegrationpatterns.com и получить книгу. Настоятельно рекомендуется.
Редактировать:
Вот пример с системой заказов. Я пропущу некоторые данные, которые понадобятся объектам, чтобы упростить пример, и попытаюсь сосредоточиться на важных частях, таких как CDM и внутренняя модель.
ПРИМЕЧАНИЕ Для простой пример, всегда трудно обосновать некоторые решения, так как с дополнительными вещами большинство вещей будет намного проще. Реализация сделана таким образом, чтобы помочь с примером.
Прежде чем я продолжу: Наличие CDN будет иметь некоторые накладные расходы при переводе с внутренней на внешнюю модель. Если вы думаете, что вы можете go без него, сделайте это. Не делайте вещи более сложными, чем они должны быть. Проблема здесь в том, что если вам нужно изменить команду или событие, это распространится на все службы и вызовет огромный волновой эффект в вашей системе. В книге «Проектирование под управлением домена» есть раздел, посвященный антикоррупционному слою. Проверьте это.
Почему мы используем CDM? Для Инкапсуляция . Точно так же, как объект инкапсулирует свои данные, сервис инкапсулирует свои внутренние компоненты. CDM предназначен для использования только для связи / интеграции между службами и предназначен для совместного использования между ними.
Совместное использование внутренней модели услуги с другими службами - это плохо, поскольку разработчики не смогут изменить эту Внутреннюю модель . Также иногда детали из одного сервиса могут просочиться в другие сервисы и могут вызвать огромные проблемы.
Совместное использование Специальная модель данных , предназначенная только для связи между сервисами, является хорошей вещью, поскольку она обеспечивает хороший определенная модель для связи, и ваша система не станет беспорядком событий и команд с неизвестными схемами, где каждый Сервис отправляет и потребляет все, что ему нравится. Я видел такие ужасы, поверьте мне, вы этого не хотите!
Эта модель должна быть разработана на более высоком уровне абстракции: на уровне системы, с учетом ее процессов и потоков. Следует исключить какие-либо подробности о внутренних функциях отдельных служб.
Вам нужно Перевод между внутренней и внешней моделями. Кроме того, вы можете использовать ContentFilter и ContentEnricher , если вам нужно отфильтровать входящие события или команды и добавить дополнительные данные к исходящим событиям или командам.
// Canonical Data Model
namespace CDM {
public interface ICommand { }
public interface IEvent { }
public class CustomerInfo {
public Guid Id { get; set; }
// notice here the CDM uses the two separate properties for the first and last name
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class LineItemData {
public Guid ProductId { get; set; }
public Quantity Quantity { get; set; }
public Money ListPrice { get; set; }
}
public class PlaceOrderCommand : ICommand {
public CustomerInfo CustomerInfo { get; set; }
public IReadOnlyList<LineItemData> LineItems { get; set; }
}
public class OrderPlacedEvent : IEvent {
public Guid OrderId { get; set; }
public IReadOnlyList<LineItemData> LineItems { get; set; }
}
} // end Canonical Data Model namespace
// Order Service Internals
// the name is done this way to differentiate between the CDM
// and the internal command, do not use it this way into production
public class LineItem {
// the internal one includes the OrderId { get; set; }
public Guid OrderId { get; set; }
public Guid ProductId { get; set; }
public Quantity Quantity { get; set; }
public Money ListPrice { get; set; }
}
public class PlaceOrderInternalCommand {
public Guid CustomerId { get; set; }
public string CustomerFullName { get; set; } // a single full name here
public IReadOnlyList<LineItemData> LineItems { get; set; }
}
public class Event { }
public class OrderPlacedInternalEvent : Event {
public Guid OrderId { get; set; }
public IReadOnlyList<LineItem> { get; set; }
}
// this is part of the infrastructure, received messages and translates/transforms
//them from the external CDM to the internal model.
// This is the input/receiving part of the service
public class CommandDispatcher {
public void Dispatch(ICommand cmd) {
// here we will use a MessageTranslator, check PatternsUsed section
var translator = TranlatorsRegistry.GetFor(cmd);
var internalCommand = translator.Translate(cmd);
Dispatch(internalCommand);
}
}
public class CommandHandler {
public void Handle(PlaceOrderInternlCommand cmd) {
// this will create the OrderCreated event
var order = CreateOrder(cmd);
// this will save the OrderCreated event
OrderRepository.Save(order);
}
}
// Another part of the infrastructure that publishes events.
// This is the output/sending part of the service
public class EventPublisher {
public void Publish(Event event) {
// another usage of the MessageTranslator pattern, this time on events
var translator = EventTranslatorRegisty.GetFor(event);
var cdmEvent = translator.Translate(event);
// publish to kafka or whatever you are using
PubilshToMessageMiddleware(cdmEvent);
}
}
Используемые шаблоны :
Каноническая модель данных MessageTranslator CommandMessage EventMessage