Когда класс или модуль должны находиться в отдельной сборке / DLL?

22

Существуют ли рекомендации для принятия решения, когда класс должен находиться в своей сборке / DLL? Я часто вижу две школы мысли:

1) Каждая «группа» классов принадлежит своей собственной DLL, например, репозитории, сервисы, DTO, инфраструктура и т. Д.

2) Все должно быть в одной DLL, но разделено через пространства имен / папки, например, иметь «Core» DLL с дополнительными пространствами имен, например Core.Repositories, Core.Services, Core.DTO и т. Д.

На работе мы просто объединяем все в одну сборку под названием «Бизнес». Есть несколько папок, но нет реального разделения - бизнес-объекты (с логикой, некоторые из которых не должны быть даже классами) без заботы помещаются в папку «BusinessObjects». Вещи, используемые более чем в одном классе, находятся в папке «Core». Утилиты находятся в папке «Утилиты», инфраструктура доступа к данным - это папка «Данные».

Для нового модуля, над которым я работаю, я хочу / должен иметь отдельный слой доступа к данным (представьте, как элементарную реализацию репозитория), но я не хочу просто бросать его в папку «BusinessObjects» с другими 160 (!) занятия там. В то же время я обеспокоен созданием новой библиотеки классов, поскольку каждый привык вставлять класс в одну библиотеку; однако папка / пространство имен может работать.

Уэйн Молина
источник

Ответы:

12

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

Например, исходя из того, что вы упомянули, у меня наверняка будут следующие проекты:

  • ядро
  • Данные
  • Домен (или BusinessObjects)
  • Сервисы
  • Утилиты (или Помощники)
Бернард
источник
2
К сожалению, я не могу проголосовать за ответ. Это именно то, что рекомендуется в нашей фирме. В результате, имея около 6 проектов, например, для веб-сайта среднего размера, вы не можете поддерживать функциональную иерархию каталогов и т. Д. В результате вы получаете шесть проектов, в каждом из которых сложная куча файлов. Обычно люди, которые советуют это, никогда не пробовали основанную на особенностях структуру проектов относительно больших проектов (извините за прямое суждение, но иметь дело с результатами такого перегиба - реальная боль). Ответ Jammycakes советует правильный подход.
Alehro
Разделение классов по категориям - вот что приводит к путанице в больших проектах. Разделите их по признакам / аспектам. Тогда пространства имен будут просто отражать это разделение. И вся структура будет отражать лексикон из спецификации. Разделение классов по категориям похоже на добавление сокращений типов к именам переменных - обычно это неприятный запах.
Alehro
Легко злоупотреблять обоими предлагаемыми решениями (т.е. слишком много проектов или слишком мало). Нахождение хорошего баланса с учетом возможности повторного использования и слабой связи должно привести к чему-то более проверяемому и поддерживаемому.
Бернард
16

«Дядя Боб» Мартин из Clean Code, известность SOLID Principles, изложил здесь три принципа :

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

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

jammycakes
источник
2
+1 эти принципы хорошие рекомендации. Разделение классов на разные сборки вносит дополнительные конструктивные соображения (например, с какими версиями каждой сборки разрешено работать вместе), увеличивая общую кодовую базу, тем самым увеличивая стоимость обслуживания.
Бен
1
Однако в дополнение к этим принципам я хотел бы добавить, что нередко рекомендуется упаковывать код, который может быть заменен или заменен в отдельной сборке. Этот код извлечет выгоду из дополнительных соображений, необходимых для соединения отдельных сборок, а его раздельное упрощает тестирование и сравнение различных версий.
Бен
4
Да, но убедитесь, что есть подлинное требование для его замены или замены. Например, фреймворки и сторонние библиотеки - пакеты NuGet и т. П. - обычно должны поддерживать несколько контейнеров IOC и несколько каркасов журналирования. С другой стороны, для пользовательского кода такие абстракции обычно носят чисто умозрительный, ненужный и обструктивный характер и никогда не срабатывают в конце в тех редких случаях, когда они действительно необходимы.
jammycakes
«Разделяйте их только в том случае, если вам нужно сделать это для реализации одного или нескольких конкретных пользовательских историй, или если одна сборка вызывает измеримые проблемы с производительностью (обычно, когда они достигают размера в несколько мегабайт)». - совершенно случайный и не основанный на реальности совет
хянков
1
Извините, но что именно "абсолютно случайно и не основано на реальности"? Я опубликовал этот ответ после нескольких лет работы над решениями, которые были разбиты на гораздо большее количество проектов, чем необходимо, без какой-либо причины, кроме как именно так вы должны это делать. Результат? Время ледниковой компиляции и адская зависимость (особенно в дни до NuGet). Разделение элементов на отдельные сборки имеет свою стоимость, и если нет никакой выгоды, чтобы компенсировать эти затраты, то это просто случай кражи из бизнеса.
jammycakes
4

Некоторые другие руководящие принципы, с которыми я работаю:

  • Как вы думаете, вы будете повторно использовать этот код в других проектах? Для одной группы связанных веб-приложений у нас был один модуль, связанный с учетными записями пользователей, который использовался во всех приложениях, поскольку все они использовали одну и ту же модель для учетных записей пользователей и входа в систему. Я делал подобные вещи с библиотеками геометрии и математики и повторно использовал их в нескольких приложениях, просто включив DLL.

  • Вы хотите иметь возможность изменять / развертывать этот код без повторного развертывания / перекомпиляции всего проекта? Иногда было полезно просто перестроить модуль, развернуть и перезапустить веб-приложение.

Похоже, что в вашем случае базовый и универсальный репозиторий может быть снова полезен в будущем, возможно, стоит разделить его на новую DLL, если вы можете.

FrustratedWithFormsDesigner
источник
Я думаю, что ваше второе замечание действительно разумно. Разделение на модули должно помочь в разработке / тестировании и времени компиляции.
WM