Подтвердить что ты не робот

Структурирование проектов и зависимостей приложений больших winforms в С#

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


Как вы структурируете очень большое приложение?

  • Несколько небольших проектов/сборок в одном большом решении?
  • Несколько крупных проектов?
  • Одно решение для каждого проекта?

И как вы управляете зависимостями в случае, когда у вас нет одного решения. Примечание. Я ищу совет, основанный на опыте, а не ответы, которые вы нашли в Google (я могу сделать это сам).

В настоящее время я работаю над приложением, которое имеет 80 библиотек DLL, каждый в своем собственном решении. Управление зависимостями - это почти полная работа. Существует собственный собственный "источник управления" с добавленной функциональностью для копирования библиотек зависимостей повсюду. Кажется, для меня является оптимальным решением, но есть ли лучший способ? Боюсь, что работа над решением с 80 проектами будет довольно сложной.

(Контекст: winforms, а не веб-интерфейс)

EDIT: (Если вы считаете, что это другой вопрос, оставьте мне комментарий)

Мне кажется, что существуют взаимозависимости между:

  • Структура проекта/решения для приложения
  • Папка/Структура файла
  • Структура ветки для управления версиями (если вы используете ветвление)

Но я с большим трудом отделяю их, чтобы рассматривать их индивидуально, если это возможно.

Я задал другой связанный с ним вопрос здесь.

4b9b3361

Ответ 1

Контроль источника

У нас есть 20 или 30 проектов, которые встроены в 4 или 5 дискретных решений. Мы используем Subversion для SCM.

1) У нас есть одно дерево в SVN, содержащее все проекты, организованные логически по пространству имен и имени проекта. В корне есть .sln, который будет их создавать, но это не является обязательным требованием.

2) Для каждого фактического решения у нас есть новая папка trunks в SVN с SVN: Внешние ссылки на все необходимые проекты, чтобы они обновлялись из их местоположений под основным деревом.

3) В каждом решении есть .sln файл плюс несколько других необходимых файлов, а также любой код, который уникален для этого решения и не используется совместно с решениями.

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

Архитектура Мы полностью переключились на использование MS SCSF и CAB enterprise для управления тем, как наши различные проекты объединяются и взаимодействуют в интерфейсе Win Forms. Я не уверен, что у вас одни и те же проблемы (несколько модулей должны совместно использовать пространство в среде общих форм), но если вы это сделаете, это может привести к некоторому здравому смыслу и соглашению о том, как вы архитект и собираете свои решения.

Я упоминаю, что поскольку SCSF имеет тенденцию объединять функции типа BO и UI в один и тот же модуль, тогда как ранее мы придерживались строгой политики уровня 3:

FW - Рамочный код. Код, функция которого относится к программному обеспечению. BO - Бизнес-объекты. Код, функция которого относится к проблемной области. UI - код, который относится к пользовательскому интерфейсу.

В этом сценарии зависимостей строго UI → BO → FW

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

Ответ 2

Чтобы управлять зависимостями, независимо от количества собраний/пространств имен/проектов у вас есть, вы можете взглянуть на инструмент NDepend.

Personnaly, я придумываю несколько крупных проектов в рамках одного или нескольких решений, если это необходимо. Я написал о моих мотивах, чтобы сделать это здесь: Воспользуйтесь преимуществами компиляторов С# и VB.NET perf

Ответ 3

Я думаю, что очень важно, что у вас есть решение, содержащее все ваши 80 проектов, даже если большинство разработчиков используют большинство других решений большую часть времени. По моему опыту, я стараюсь работать с одним большим решением, но чтобы избежать боли при восстановлении всех проектов каждый раз, когда я нажимаю F5, я иду в Solution Explorer, щелкните правой кнопкой мыши на проектах, которые мне сейчас не интересны, и выполните "Выгрузить проект". Таким образом, проект остается в решении, но мне это ничего не стоит.

Сказав, что 80 - большое число. В зависимости от того, насколько хорошо эти 80 разбиваются на подсистемы dicrete, я могу также создать другие файлы решений, каждая из которых содержит значимое подмножество. Это спасло бы меня от многих операций щелчка правой кнопкой мыши/разгрузки. Тем не менее, тот факт, что у вас есть одно большое решение, означает, что всегда существует окончательное представление об их взаимозависимостях.

Во всех системах управления версиями, с которыми я работал, их VS-интеграция решает поставить файл .sln в исходный элемент управления, и многие из них не работают должным образом, если этот .sln файл не находится в исходном управлении. Я считаю это интригующим, поскольку файл .sln считался личным делом, а не просто проектом. Я думаю, что единственный вид файла .sln, который определенно заслуживает контроля над версиями, - это "одно-большое решение", содержащее все проекты. Например, вы можете использовать его для автоматических сборок. Как я уже сказал, люди могут создавать свои собственные решения для удобства, и я не против тех, кто входит в исходный контроль, но они более значимы для людей, чем для проекта.

Ответ 4

Я думаю, что лучшим решением является разбить его на более мелкие решения. В компании, в которой я сейчас работаю, у нас та же проблема; 80 проектов ++ в решении. То, что мы сделали, состоит в том, чтобы разделить на несколько небольших решений с проектами, принадлежащими друг другу. Зависимая dll от других проектов строится и привязывается к проекту и проверяется в исходной системе управления вместе с проектом. Он использует больше дискового пространства, но диск дешевый. Таким образом, мы можем остаться с версией 1 проекта, пока не потребуется обновление до версии 1.5. У вас все еще есть работа с добавлением dll при решении перейти на другую версию DLL. Существует проект кода google под названием TreeFrog, который показывает, как структурировать дерево решений и разработки. Он еще не содержит документацию mush, но я думаю, вы можете получить представление о том, как это сделать, если посмотреть на структуру.

Ответ 5

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

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

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

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

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

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

Ответ 6

Для нескольких систем, над которыми я работал, у нас были разные решения для разных компонентов. Каждое решение имело общую папку вывода (с подпапками Debug и Release)

Мы использовали ссылки на проекты в рамках решения и ссылки на файлы между ними. В каждом проекте использовались ссылочные пути для поиска сборок из других решений. Нам пришлось вручную отредактировать файлы .csproj.user, чтобы добавить переменную msbuild в переменную $(Configuration) в ссылочные пути, поскольку VS настаивает на проверке пути.

Для сборки вне VS я написал сценарии msbuild, которые рекурсивно идентифицируют зависимости проекта, извлекают их из подрывной деятельности и строят их.

Ответ 7

Я отказался от ссылок на проекты (хотя ваши макросы звучат замечательно) по следующим причинам:

  • Невозможно было переключиться между различными решениями, где иногда существовали проекты зависимостей, а иногда и нет.
  • Необходимо иметь возможность самостоятельно открывать проект и строить его, а также развертывать его независимо от других проектов. Если они были построены с использованием ссылок на проекты, это иногда вызывало проблемы с развертыванием, потому что ссылка на проект заставляла его искать определенную версию или выше или что-то в этом роде. Он ограничил возможность соединения и сопоставления для обмена различными версиями зависимостей.
  • Кроме того, у меня были проекты, указывающие на разные версии .NET Framework, и поэтому истинная ссылка на проект не всегда происходила.

(FYI, все, что я сделал, для VB.NET, поэтому не уверен, что какая-либо тонкая разница в поведении для С#)

Итак, I:

  • Я строю против любого проекта, открытого в решении, и тех, которые не являются, из глобальной папки, таких как C:\GlobalAssemblies
  • Мой сервер непрерывной интеграции постоянно обновляет сетевой ресурс, и у меня есть пакетный файл для синхронизации чего-либо нового с моей локальной папкой.
  • У меня есть еще одна локальная папка, такая как C:\GlobalAssembliesDebug, где каждый проект имеет шаг пост-сборки, который копирует содержимое папки bin в эту папку отладки, только в режиме DEBUG.
  • Каждый проект имеет эти две глобальные папки, добавленные к их ссылочным путям. (Сначала C:\GlobalAssembliesDebug, а затем C:\GlobalAssemblies). Мне нужно вручную добавить эти ссылочные пути в файлы .vbproj, потому что пользовательский интерфейс Visual Studio добавляет их в файл .vbprojuser.
  • У меня есть шаг предварительной сборки, который, если в режиме RELEASE удаляет содержимое из C:\GlobalAssembliesDebug.
  • В любом проекте, который является хост-проектом, если есть не DLL, которые мне нужно скопировать (текстовые файлы, выводимые в другие папки bin проекта, которые мне нужны), я помещаю шаг предварительной сборки на этот проект, чтобы скопировать их в хост проекта.
  • Мне нужно вручную указать зависимости проекта в свойствах решения, чтобы они были построены в правильном порядке.

Итак, что это значит:

  • Позволяет мне использовать проекты в любом решении без использования ссылок на проекты.
  • Visual Studio по-прежнему позволяет мне входить в проекты зависимостей, которые открыты в решении.
  • В режиме DEBUG он создается против открытых загруженных проектов. Итак, сначала он смотрит на C:\GlobalAssembliesDebug, а если нет, то C:\GlobalAssemblies
  • В режиме RELEASE, поскольку он удаляет все из C:\GlobalAssembliesDebug, он смотрит только на C:\GlobalAssemblies. Причина, по которой я хочу, так это то, что выпущенные сборки не построены на том, что было временно изменено в моем решении.
  • Легко загружать и выгружать проекты без особых усилий.

Конечно, это не идеально. Опыт отладки не так хорош, как ссылка на проект. (Не могу делать такие вещи, как "перейти к определению" и правильно ли это работать) и некоторые другие причудливые вещи.

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

Ответ 8

У нас есть одно гигантское решение по управлению источником, на главной ветке.

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

Однако для этого есть одно условие: в решении не должно быть слишком много взаимосвязанных проектов.

Ответ 9

ОК, переварив эту информацию, а также ответ на этот вопрос о ссылках на проект, я сейчас работаю с этой конфигурацией, которая, кажется, "работает для меня" ":

  • Одно большое решение, содержащее проект приложения и все проекты сборки зависимостей
  • Я сохранил все ссылки на проекты, с некоторой дополнительной настройкой ручных зависимостей (щелкните правой кнопкой мыши по проекту) для некоторых динамически созданных сборок.
  • У меня есть три папки Solution (_Working, Synchronized и Xternal) - если мой исходный элемент управления не интегрирован с VS (sob), это позволяет мне быстро перетаскивать проекты между _Working и Synchronized, t потерять след изменений. Папка XTernal предназначена для сборок, которые "принадлежат" коллегам.
  • Я создал себе конфигурацию "WorkSetOnly" (последняя опция в раскрывающемся списке Debug/Release), которая позволяет мне ограничить проекты, которые перестраиваются на F5/F6.
  • Что касается диска, у меня есть все папки моих проектов в одной из нескольких папок (так что только один уровень категоризации над проектами)
  • Все проекты строят (dll, pdb и xml) в одну и ту же папку вывода и имеют ту же папку, что и ссылочный путь. (И все ссылки заданы как "Не копировать" ) - это оставляет мне возможность отказаться от проекта из моего решения и легко переключиться на ссылку на файл (у меня есть макрос для этого).
  • На том же уровне, что и в моей папке "Проекты", у меня есть папка "Решения", где я поддерживаю отдельные решения для некоторых сборок - вместе с тестовым кодом (например) и документацией/дизайном и т.д., специфичными для сборки.

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

В настоящее время неразрешенные недостатки:

  • У меня все еще есть проблемы с отдельными решениями сборки, поскольку я не всегда хочу включать все зависимые проекты. Это создает конфликт с "основным" решением. Я работал над этим с (снова) макросом, который преобразует сломанные ссылки на ссылки на ссылки на файлы и восстанавливает ссылки на ссылки на проекты, если проект добавлен обратно.
  • К сожалению, к сожалению, нет пути (который я нашел до сих пор) для связывания конфигурации сборки с папками решений - было бы полезно иметь возможность сказать "собрать все в этой папке" - поскольку это так, я должен обновить эту (болезненным и легко забываемым). (Вы можете щелкнуть правой кнопкой мыши по папке решения для сборки, но это не относится к сценарию F5)
  • В реализации папки Solution есть (незначительная) ошибка, которая означает, что при повторном открытии решения проекты отображаются в том порядке, в котором они были добавлены, а не в алфавитном порядке. (Я открыла ошибку с MS, видимо, теперь исправлена, но я думаю, для VS2010)
  • Мне пришлось удалить надстройку CodeRushXPress, потому что она задыхалась от всего этого кода, но это было до изменения сборки config, поэтому я собираюсь дать ему еще одну попытку.

Резюме - вещи, которые я не знал, прежде чем задавать этот вопрос, который оказался полезным:

  • Использование папок решений для организации решений без использования диска
  • Создание конфигураций сборки для исключения некоторых проектов
  • Возможность вручную определять зависимости между проектами, даже если они используют ссылки на файлы

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