Совместное использование типов в модульной архитектуре приложения - PullRequest
1 голос
/ 28 сентября 2011

У меня есть приложение, которое разрабатывается в соответствии с модульным дизайном приложения. Существует «базовый» вертикальный стек, который обеспечивает общие центральные службы, такие как аутентификация / авторизация, ведение журнала, доступ к данным и т. Д. Контекстные области реализованы в модулях, которые ссылаются на базовую сборку на одном и том же логическом уровне.

Приложение представляет собой сервисное приложение с фасадным уровнем, доменным уровнем и кодом инфраструктуры, содержащим код доступа к данным. Каждый модуль будет реализовывать сборку на уровне домена. Если у модуля есть открытый API, он также реализует сборку фасада.

Например, решение содержит:

Core.Api - Фасадная сборка для основного API Core - сборка домена для основных служб, объектов и т. Д. Core.Data - сборка доступа к данным ядра
ModuleA.Api - Фасадная сборка для модуля A (ссылки Core.Api) Модуль A - Сборка домена для модуля A (ссылается на Core)
ModuleB.Api - Фасадная сборка для модуля B (ссылки Core.Api) ModuleB - Сборка домена для модуля B (ссылается на Core)

enter image description here

(и т. Д. Когда закончим, у нас будет около 24 модулей.)

Все это связано с использованием DI с Unity в качестве контейнера IoC. Проект WebHost определяет конфигурацию, в которой различные реализации сопоставляются с интерфейсами, которые они заполняют.

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

Мой вопрос заключается в том, что делать, если для ModuleB требуется один или несколько типов, определенных в ModuleA? Допустимо ли для ModuleB ссылаться на ModuleA или мне нужно переместить ModuleA в ядро?

UPDATE

Рассматривая реализацию некоторых из рассмотренных ниже изменений, я столкнулся с ошибкой, которая приводит меня к этому разъяснению ...

Есть два места, где мои модули взаимозависимы. Следуя подходу, обсуждаемому ниже, я могу переместить интерфейсы и типы, которые я хочу использовать совместно, из Module1 в Core, что позволяет ModuleB использовать их без тесной связи между ModuleA и ModuleB. Однако мне также необходимо использовать некоторые из контрактов данных, определенных в ModuleA.Api, для операций сервиса в ModuleB.Api. Это заставляет меня сомневаться в дизайне.

Из-за IP я не могу описать наш точный вариант использования, но достаточно сказать, что ModuleA имеет объект домена EntityA. ModuleA.Api определяет контракт данных EntityContractA (DTO), предоставляемый общедоступным API. ModuleB.Api имеет метод, который требует EntityContractA в качестве параметра, а затем делегирует метод в ModuleB, который принимает EntityA в качестве параметра.

Опять же, перемещение EntityA в Core решает проблему доменного уровня, но не помогает мне с фасадным слоем. Перемещение EntityContractA в Core.Api немного пахнет.

Вот пример того, что мне нужно сделать:

В ModuleB.Api.ServiceFacadeB:

public EntityContractB FilterBy(EntityContractA contractA)
{
    var entityA = Mapper.Map<EntityContractA, EntityA>(contractA);

    var entityB = domainService.FilterBy(entityA);

    var contractB = Mapper.Map<EntityB, EntityContractB>(entityB);

    return contractB;
}

, где domainService - это ModuleA.ServiceB:

public EntityB FilterBy(EntityA entityA)
{
    // Do work
}

Ответы [ 3 ]

0 голосов
/ 28 сентября 2011

Хорошая новость: то, что вы описываете, на самом деле - хорошая архитектура с четким разделением проблем и шаблонных моделей.Это позволяет вашим командам разрабатывать модули независимо друг от друга и зависеть только от интерфейсов друг друга (фасад / API).Это лучшая практика!

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

Мое предложение: если вам нужен тип в Module2, который сейчасопределенный в Module1, убедитесь, что вы переместили его в Core API или в классы Module1 API.Это формализует тот факт, что ваша сборка зависит от этих типов, и дает понять, что они должны быть стабильными.

0 голосов
/ 30 сентября 2011

Допустимо ли для ModuleB ссылаться на ModuleA или мне нужно переместить ModuleA в ядро?

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

[Предупреждение, самореклама:] В представлении 5-Layer Architecture о мире они будут отображаться«Общий» слой.

0 голосов
/ 28 сентября 2011

Модуль 2 должен иметь ссылку на Модуль 1.взаимозависимость между модулями не дает оснований для перемещения частей в общий код ядра.

...