Связь между ограниченными контекстами

У меня есть приложение WinForms, которое я надеюсь провести рефакторинг для использования архитектуры DDD. Во-первых, я пытаюсь по-настоящему погрузиться в саму архитектуру, у меня есть книга Эванса и книга Вернона, и я обнаруживаю, что борюсь с тремя сценариями, с которыми я бы сразу столкнулся в своем приложении. Боюсь, что я слишком много обдумываю или слишком строг в процессе концептуального проектирования.

1.) Используя пример из учебника Pluralsight по DDD, докладчик подчеркнул, что различные ограниченные контексты должны быть представлены их собственным решением. Однако, если у меня есть приложение winforms, которое не ориентировано на сервисы (со временем это изменится, и многие из этих вопросов станут спорными), это не представляется возможным. Поэтому я исхожу из предположения, что я буду разделять их на разные проекты / пространства имен, проявляя бдительность, чтобы не было взаимозависимостей. Это правильный способ думать об этом или я упускаю что-то очевидное?

2.) У меня есть пользовательский интерфейс навигации, который запускает другие модули / окна, которые принадлежат отдельным уровням представления в разных ограниченных контекстах. Подумайте о первом окне, которое откроется, когда вы запустите приложение ERP. Поскольку это не совсем вписывается в какой-либо конкретный BC, как можно было бы правильно реализовать что-то подобное. Должно ли это относиться к общему ядру?

3.) У меня есть ограниченный контекст управления заданиями и ограниченный контекст рейтинга / стоимости. Это часть бизнес-процесса, когда при создании задания оцениваются его детали. У него есть собственный пользовательский интерфейс и т. Д., И я считаю, что эта презентация адекватно попадает в контекст управления заданиями. Однако в фактическом процессе рейтинга этих деталей точно не должно быть. Я не совсем уверен, как взаимодействовать с контекстом рейтинга / стоимости, поскольку bc должны храниться отдельно друг от друга. Я понимаю, что могу обмениваться сообщениями, но это кажется излишним для нераспределенного приложения. Каждый BC может иметь возможность самостоятельно размещать какой-либо API, но, опять же, это кажется излишним, хотя это могло бы хорошо подготовить команду к переходу на распределенную архитектуру в дальнейшем. Наконец, моя последняя идея - иметь некую общую зависимость, которая является своего рода хранилищем событий. Я не знаю, совпадает ли это с событиями домена, поскольку они, кажется, вызывают отдельную озабоченность сами по себе. Итак, означает ли это, что это также подпадает под общее ядро ​​или какой-либо другой тип решения?

Заранее спасибо.


person joshlrogers    schedule 24.05.2013    source источник


Ответы (3)


1) Рекомендации по BC, соответствующим решению, - это только руководство, а не жесткое правило. Однако он обеспечивает столь необходимую изоляцию. Вы все еще можете получить это с помощью проекта WinForms. Например, предположим, что у вас есть BC под названием «Клиенты». Создайте для него решение и в нем создайте дополнительный проект под названием Customers.Contracts. В этом проекте фактически размещается публичный контракт BC, который состоит из DTO, команд и событий. Внешние BC должны иметь возможность связываться с клиентом BC, используя только сообщения, определенные в этом проекте контрактов. Решение WinForms должно ссылаться на Customers.Contracts, а не на проект Customers.

2) Пользовательский интерфейс часто выполняет составную роль, управляя многими BC - составным пользовательским интерфейсом. Стереотипный пример - страница продукта Amazon. Для рендеринга страницы требуются сотни сервисов из разных BC.

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

person eulerfx    schedule 24.05.2013

Ощущение, которое я получаю от этих вопросов, можно резюмировать следующим образом: «Каков разумный подход к границам BC с точки зрения артефактов кода? И Как мне создать пользовательский интерфейс, который одновременно запрашивает и управляет несколькими BC?». Это зависит ...

Другой, еще не упомянутый подход может заключаться в рассмотрении пользовательского интерфейса как отдельного контекста. Я сомневаюсь, что это очень популярный POV, но иногда он может быть полезен. Пользовательский интерфейс может диктовать, что ему нужно, например свои собственные интерфейсы и структуры данных, и пусть каждый BC реализует соответствующие интерфейсы (выполняет внутреннюю трансляцию). Обратной стороной является дополнительный перевод, но опять же, это имеет смысл только тогда, когда есть достаточная ценность, которую можно пожинать. Ценность состоит в том, чтобы упростить работу со стороны пользовательского интерфейса и не беспокоиться о том, как и откуда поступают данные или как изменения влияют на каждый BC. Со всем этим можно справиться за простой фасад. Этот фасад может располагаться в нескольких местах (на клиенте или на сервере). Не дайте себя обмануть, «сложность» только что переместилась за еще один слой. По-прежнему необходимы координация и упорная работа.

В качестве альтернативы вы также можете изучить то, что я называю «согласованием» пользовательского интерфейса с вариантами использования, предоставляемыми BC. Как упоминал Том, реализация рабочего процесса или саги может пригодиться, чтобы осуществить это, когда требуется координация. Если поставить под сомнение требования согласованности (когда этот другой BC должен знать о данной информации?), Можно по-новому взглянуть на то, как взаимодействуют BC. Видите ли, пользовательский интерфейс - это очень полезный цикл обратной связи. Когда он не согласован с вариантом использования BC, возможно, что-то не так с вариантом использования, или, может быть, что-то не так с тем, как он был разработан в пользовательском интерфейсе, или, может быть, мы просто обнаружили другой вариант использования. Вот почему макеты пользовательского интерфейса - отличный инструмент для обсуждения. Они предлагают ДОПОЛНИТЕЛЬНЫЙ взгляд на одну и ту же проблему / решение. Дополнительно, например, «это не единственная визуализация, которую следует использовать в беседах с экспертом в предметной области». Требования к UX - тоже требования. Их следует обслужить.

Лично я считаю, что когда я обсуждаю UI, я ношу другую шляпу, чем когда я обсуждаю чистую функциональность (вы знаете, вещи, которые не требуют UI, чтобы объяснить, что приложение делает / должно делать). Я мог бы сменить шляпу во время одного и того же разговора, просто чтобы обнаружить несогласованность.

person Yves Reynhout    schedule 26.05.2013

Перво-наперво, поскольку я видел, как вы говорили о шине сообщений, я думаю, что нам нужно сначала поговорить об интеграции BC.

Для связи между BC вам не нужна шина сообщений; вот объяснение того, как я интегрирую разные BC:

Я предоставляю несколько общедоступных интерфейсов для каждого BC (аналогично командам домена, - запросам и - событиям) и имею промежуточный уровень в моей инфраструктуре, который транслирует этот вызов в другой BC.

Вот пример интерфейса для открытых команд в BC:

public interface IHandleCommands
{
    void DoSomething(Guid SomeId,string SomeName);
}

Еще у меня есть аналогичный для открытых событий

public interface IPublishEvents 
{
   void SomethingHappened(Guid SomeId,string SomeName);
}

Наконец, для моих открытых данных (то есть запросов в CQ (R) S) у меня есть другой интерфейс, обратите внимание, что это позволяет вам удалить связь между вашей моделью предметной области и кодом запроса в любой момент времени.

public interface IQueryState
{
    IEnumerable<SomeData> ActiveData(DateTime From=DateTime.Minvalue, ... );
}

И моя реализация выглядит так:

public class SomeAR:IHandleCommands
{
    IPublishEvents Bus;

    public SomeAr(IPublishEvents Bus) 
    {
       this.Bus = Bus;
    }

    public void DoSomething(Guid x,string y)
    {
       Bus.SomethingHappened(SomeId: x,SomeName: y);
    }
}

В конце концов, если подумать: такие вещи, как события предметной области, можно делать и без обмена сообщениями; просто замените классы сообщений элементами интерфейса и замените обработчики реализациями интерфейса, которые вводятся в ваш BC.

Затем эти обработчики вызывают команды на других BC; они похожи на клей, который связывает воедино различные BC (подумайте о рабочих процессах / сагах без сохранения состояния и т. д.).

Это может быть пример обработчика:

public class WorkFlow : IPublishEvents
{
  public void SomethingHappened(Guid SomeId,string SomeName) 
  {
     AnotherBC.DoSomething(SomeId,SomeName);
  }
}

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

Чтобы ответить на ваши вопросы об интерфейсе:

Я думаю, вы слишком строги в этом вопросе.

Пока мой домен (или может быть легко) отделен от вашего пользовательского интерфейса, вы можете легко начать с одного проекта пользовательского интерфейса, а затем разделить его, как только вы начнете где-то испытывать боль. Однако, если вы разделяете код, вам следует разделить его по BC, чтобы структуры проекта совпадали.

Я считаю, что создание пользовательского интерфейса для меня является наиболее эффективным способом ...

person Tom    schedule 25.05.2013