Должен ли я смешивать технологии в сборках? - PullRequest
5 голосов
/ 12 октября 2011

У меня есть проект среднего размера, в котором реализовано около 20 разных концепций. Сначала я решил организовать свои сборки на основе концептуальных слоев, например:

MyProject.Domain.dll (References System.Data.Linq, etc.)
  \ConceptA\
  \ConceptB\
  \ConceptC\
  \...\

MyProject.Presentation.dll
  \ConceptA\
  \ConceptB\
  \ConceptC\
  \...\

MyProject.WinForms.dll (References System.Windows.Forms, etc.)
  \ConceptA\
  \ConceptB\
  \ConceptC\
  \...\

MyProject.App.exe (References all the above)

Я недавно прочитал в книге DDD, что я должен группировать свои сборки на основе представляемой им концепции домена, а не на технологическом уровне, например:

MyProject.ConceptA.dll (References System.Data.Linq, System.Windows.Forms, etc.)
  \Domain\
  \Presentation\
  \WinForms\

MyProject.ConceptB.dll
  \Domain\
  \Presentation\
  \WinForms\

MyProject.ConceptC.dll
  \Domain\
  \Presentation\
  \WinForms\

MyProject.App.exe (References all the above)

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

  • Группировка по концепции облегчает поиск моего кода, поскольку все это в одном месте.
  • Группировка по технологии гарантирует, что я не буду звонить MessageBox.Show со своего доменного уровня.
  • Я со временем отключу технологии доступа к данным и представления.
  • В конце концов, все сборки будут ссылаться на главное приложение в любом случае.
  • Когда сгруппируются по концепции, куда пойдут тесты? Разве мне не нужно помещать их в отдельные сборки, чтобы они не поставлялись вместе с программой?

По вашему опыту, какой подход лучше?

Ответы [ 3 ]

2 голосов
/ 12 октября 2011

TL; DR : Вы должны выполнять оба, но не разбивайте свой проект на несколько сборок только ради этого.Разделив ваши сборки до повторно используемых компонентов , вы в конечном итоге будете использовать комбинацию обоих методов, где это уместно.


Во-первых, я бы сказал, что в зависимости от размера вашего проектаможет не потребоваться разделять наши концепции или слои на отдельные сборки - преимущества разделения кода на отдельные сборки имеют два аспекта:

  1. Позволяет другим сборкам / приложениям использовать ваш кодссылаясь на свою сборку
  2. Уменьшение размера больших сборок путем разбиения на множество более мелких сборок

Если у вас нет необходимости ни в одной из этих двух (и вы не захотите вбудущее), а затем упростите свою жизнь и просто объедините все в одну сборку.


Во-вторых, основная причина разделения кода на отдельные сборки - это повторное использование этого кода -например, если у вас есть часть логики обработки, используемая в приложении Windows Forms,выделение этого в отдельную сборку позволяет вам повторно использовать эту логику, например, в консоли или веб-приложении.По этой причине я обычно нахожу, что лучший способ - разделить понятия, например:

Company.Project.Concept.dll

Где «понятие» - это то, что вы хотите использовать повторно, будь то набор общих элементов управления Windowsили некоторая логика доступа к данным.

Обратите внимание, что при повторном использовании концепции довольно редко хочется повторно использовать все концептуальные уровни этой концепции (Domain / Presentation / WinForms).Обычно либо ваша концепция состоит только из 1 слоя (например, некоторая форма обработки), либо при повторном использовании этой концепции вас интересует только 1 или, возможно, 2 слоя.В этом случае, если ваши «Концептуальные» сборки также содержат другую дополнительную логику (например, WinForms), вы просто ссылаетесь на дополнительный код, который никогда не будет использоваться.По этой причине также нормально разделить на концептуальные слои, если они у вас есть, например:

Company.Project.Concept.Processing.dll
Company.Project.Concept.WinForms.dll

Т.е. в приведенном вами примере я выступаю за то, чтобы вы что-нибудь сделалихочу 9 сборок, а не 3:

MyProject.ConceptA.Domain.dll
MyProject.ConceptA.Presentation.dll
MyProject.ConceptA.WinForms.dll

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

  • Если никто другойсобирается использовать элементы управления Windows Forms, а затем не разбивать их на отдельные сборки
  • . Если большинство людей собираются использовать ConceptB и ConceptA вместе, объедините их в одну сборку
  • Если большинство людей захотят использовать слои Domain и Presentation вместе, объедините их в одинСборка

В качестве рабочего примера я автоматически предпочитаю разбивать небольшие проекты на две сборки - само приложение, которое содержит все «презентации» (будь то Web, WinForms, WPF или консоль).app) и еще одна сборка, которая содержит «мясо» приложения - базовую функциональность, предоставляемую вашим приложением (например, обработка изображений, поиск данных и т. д.).Это помогает, если я когда-нибудь захочу представить одну и ту же функциональность в другом стиле приложения.

Еще раз, хотя я бы ошибался на стороне слишком небольшого количества сборок, а не слишком большого - легче разделить сборку на две части.чем объединить две сборки обратно в одну. Если вы не найдете веских причин разделить сборку / проект на несколько сборок, не беспокойтесь.

1 голос
/ 12 октября 2011

Речь идет не о группировке только по концептуальным слоям и не по понятиям предметной области. Сначала подумайте, почему вы группируете или разделяете сборки:

  • Поддерживаемость: чтобы разделить проблемы и логически сгруппировать связанные концепции, вы группируете по аспектам в терминах «Домен», «Доступ к данным», «Инфраструктура», «Распределенные услуги», сохраняя разделение задач в плане абстрагирования уровней. Еще один аспект удобства сопровождения - это разделение ограниченных контекстов (бизнес-концепций), если логика вашего домена большая и сложная, поэтому вы можете иметь вложенную группировку по ограниченному контексту.

  • Возможность повторного использования: для разделения компонентов, которые могут быть повторно использованы в других контекстах или проектах

  • Динамическая замена компонентов: для разделения компонентов, которые могут быть заменены во время выполнения / развертывания, например, структура ведения журнала, уровень доступа к данным, ...

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

Пример - группировка по ограниченному контексту, а затем по абстракции слоя:

  • Company.CRM.Domain
  • Company.CRM.Repositories.NHibernate
  • Company.CRM.Repositories.EF
  • Company.CRM.Application
  • Company.Trading.Domain
  • Company.Trading.Repositories.NHibernate
  • Company.Trading.Application
  • Company.Shared.Infrastructure
  • Company.Shared.Infrastructure.Log4NetLogger
  • Company.Shared.Infrastructure.EnterpriseLibraryLogger
1 голос
/ 12 октября 2011

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

Конечно, это может быть применено и другим способом, если все ваши сборки сгруппированы по концепции, то вы можете иметь классы / структуры / и т.д., специфичные для концепции , в отличие от слоя.

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

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

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

Эти интерфейсы ничего не раскрывают в технологиях доступа к данным; лежащим в основе хранилищем может быть текстовый файл для меня все равно; он просто предоставляет средства для получения нужных мне данных и их обратной записи. Я могу переключиться с ADO.NET на LINQ-to-SQL на LINQ-to-Entities (все, что я выполнил сделано ) по моему желанию, в зависимости от необходимости.

Что касается тестирования, я тестирую на том же уровне, что и мои сборки, если у меня есть сборка:

Casper.Discovery.dll

Со следующими доменами и задачами:

Casper.Discovery.dll
    DomainA
        Models
        Data
    DomainB
        Models
        Data

Тогда у меня будет тестовая сборка:

 Casper.Testing.Discovery.dll

С той же структурой каталогов / файлов для тестов внизу. Я делаю это специально, чтобы можно было сгруппировать сборки для тестирования в папку с решениями с надписью «тестирование». Несмотря на то, что все они упорядочены правильно, даже если Testing был помещен в конце, добавление его после моего общего классификатора пространства имен тщеславия позволяет легко просматривать список, не путаясь с Testing в конце, и все портит то, что я ожидаю увидеть, если я смотрел на своего коллегу (проверяемая вещь).

...