Структурирование проектов и зависимостей больших приложений winforms в C # - PullRequest
24 голосов
/ 30 сентября 2008

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


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

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

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

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

(Контекст: winforms, а не web)

РЕДАКТИРОВАТЬ: (Если вы думаете, что это другой вопрос, оставьте мне комментарий)

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

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

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

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

Ответы [ 9 ]

5 голосов
/ 30 сентября 2008

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

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

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

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

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

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

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

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

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

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

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

2 голосов
/ 27 октября 2008

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

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

1 голос
/ 13 февраля 2012

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

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

(К вашему сведению, все, что я сделал, это для VB.NET, поэтому не уверен, есть ли какая-то тонкая разница в поведении для C #)

Итак, я:

  • Я строю против любого проекта, который открыт в решении, и тех, которые не, из глобальной папки, например C: \ GlobalAssemblies
  • Мой сервер непрерывной интеграции постоянно обновляет эту информацию в общей сетевой папке, и у меня есть пакетный файл для синхронизации всего нового с моей локальной папкой.
  • У меня есть еще одна локальная папка, например C: \ GlobalAssembliesDebug, где у каждого проекта есть шаг после сборки, который копирует содержимое своей папки bin в эту папку отладки, только в режиме отладки.
  • В каждом проекте эти две глобальные папки добавляются в их ссылочные пути. (Сначала 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. Причина, по которой я этого хочу, заключается в том, что выпущенные сборки не построены на основе чего-либо, что было временно изменено в моем решении.
  • Проекты легко загружать и выгружать без особых усилий.

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

В любом случае, именно здесь я пытаюсь заставить нас работать на лучшее.

1 голос
/ 29 сентября 2009

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

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

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

1 голос
/ 30 сентября 2008

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

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

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

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

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

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

1 голос
/ 30 сентября 2008

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

1 голос
/ 30 сентября 2008

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

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

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

0 голосов
/ 18 ноября 2008

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

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

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

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

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

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

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

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

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

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

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

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

...