Структурирование проектов и решений в Microsoft Visual Studio Team System

ОГЛАВЛЕНИЕ

В данной статье описываются различные варианты структурирования файлов решений и проектов Visual Studio, подходящие для коллективной разработки. Для группировки взаимосвязанных файлов проектов (.csproj и .vbproj) Visual Studio использует файлы решений (.sln). Выбор структуры проектов и решений очень важен, поскольку имеет ряд последствий. Например, он влияет на то, насколько легко члены групп разработки смогут извлекать и размещать решения и проекты в системе контроля версий, на механизм, используемый для описания зависимостей, а также на процессы сборки.

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


Стратегии структурирования решений и проектов

Чаще всего используются три стратегии структурирования файлов решений и проектов:

  1. Одиночное решение. При разработке небольшой системы, создается одиночное решение, в котором размещаются все проекты.
  2. Сегментированное решение. При разработке большой системы взаимосвязанные проекты группируются в разные решения. Для каждой логической группы проектов, с которой разработчик, вероятнее всего, будет работать как с совокупностью, создается отдельное решение. Затем все эти решения объединяются в одно главное решение, которое будет содержать все проекты. При таком подходе сокращается количество данных, извлекаемых из системы контроля версий, поскольку работа ведется только над определенными проектами.
  3. Несколько решений. При создании очень большой системы, требующей десятков и более проектов, следует работать с подсистемами. Для отображения зависимостей и из соображений производительности не нужно создавать главное решение, содержащее все проекты.

В общем, следует:

  1. Использовать стратегию одиночного решения, если размер получаемого в результате решения не слишком велик и не приводит к проблемам загрузки в Visual Studio.
  2. Использовать несколько решений для создания отдельных представлений подсистем приложения.
  3. Использовать несколько решений для сокращения времени загрузки решения и сокращения времени сборки для разработчиков.
При разработке структуры проектов и решений следует иметь в виду следующее:
  1. Каждый проект во время компиляции создает отдельную сборку (assembly). Начните с определения того, какие сборки потребуется создать, и затем, исходя
  2. из этого, принимайте решение о необходимых проектах. На основании этого распределите код по проектам.
  3. Начинайте с самой простой структуры одиночного решения. Усложняйте структуру только в том случае, когда это действительно необходимо.
  4. При проектировании структуры с множеством решений:
    1. Рассмотрите зависимости проекта. Попытайтесь сгруппировать взаимосвязанные проекты в одно решение. Это позволит использовать в решении ссылки на проекты, а не на файлы, что обеспечивает возможность Visual Studio синхронизировать конфигурации сборки (отладка/ версия для выпуска) и, отслеживая версии, определять, когда необходимо повторно собрать проект. Пытайтесь свести к минимуму количество перекрестных ссылок на проекты между решениями.
    2. Рассмотрите возможность совместного использования исходного кода. Поместите проекты, использующие один и тот же исходный код, в одно решение.
    3. Учтите структуру группы. Решения должны быть структурированы таким образом, чтобы упростить группам работу с набором взаимосвязанных проектов.
  5. Придерживайтесь плоской структуры проекта. Это облегчит задачу по группировке проектов в решения без необходимости внесения изменений в структуру каталогов или папку системы контроля версий.


Одиночное решение

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


Рис. 3.1 Подход с использованием одиночного решения
Главными причинами выбора данной структуры являются:
  1. Простые сценарии сборки.
  2. В рамках решения можно без труда отображать зависимости между проектами.
Такая структура должна использоваться, если все разработчики работают с одним и тем же решением и располагают одним и тем же набором проектов. Это может быть проблематичным для больших систем, где требуется организовать проекты по подсистемам или по функциональным возможностям.


Сегментированное решение

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

Примечание: В отличие от предыдущих версий, Visual Studio 2005 полагается в сборке проектов на MSBuild. Начиная с Visual Studio 2005, появилась возможность создавать структуры решений, не включающие в себя все проекты, на которые имеются ссылки, и такие решения все равно будут собираться без ошибок. Поскольку главное решение собирается первым, формируя результирующие двоичные файлы каждого проекта, MSBuild может прослеживать ссылки на проекты вне границ решения и успешно выполнять сборку. Но это возможно только в случае использования ссылок на проекты, а не ссылок на файлы. Созданные таким образом решения можно успешно собирать из командной строки Visual Studio и из IDE, но не с помощью Team Build. Чтобы успешно создать сборку с помощью Team Build, необходимо использовать главное решение, включающее все проекты и зависимости. На рис. 3.2 показан подход с использованием сегментированного решения.


Рис. 3.2 Подход с использованием сегментированного решения
 
При работе с несколькими решениями все проекты должны иметь плоскую структуру. Типичный пример – приложение, включающее проект Microsoft Windows® Forms, проект ASP.NET, службу Windows и ряд библиотек классов, которые совместно используются некоторыми или всеми перечисленными проектами. Для всех проектов может использоваться следующая плоская структура: /Source /WinFormsProject /WebProject
/Source 
    /WinFormsProject
    /WebProject
    /WindowsServiceProject
    /ClassLibrary1
    /ClassLibrary2
    /ClassLibrary3
    Web.sln
    Service.sln
    All.sln

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

Основания использования этой структуры:

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

Основная причина не использовать эту структуру:

  1. Повышение затрат на обслуживание решения. Введение нового проекта может повлечь за собой изменение файлов многих решений.


Несколько решений

При работе над очень большим решением, включающим десятки проектов, может возникнуть проблема с масштабируемостью решения. При таком сценарии следует разбить приложение на несколько решений, но при этом не создавать главного решения для всего приложения, потому что все ссылки внутри решений являются ссылками на проекты. Ссылки на проекты вне решений (например, на библиотеки сторонних производителей или проекты из другого составляющего решения) – это ссылки на файлы, т.е. без «главного» решения можно обойтись.
Вместо главного решения необходимо использовать сценарий, который понимает порядок сборки решений. Одна из главных задач при обслуживании структуры с несколькими решениями – гарантировать невозможность создания циклических ссылок между решениями. Эта структура требует сложных сценариев сборки и явного отображения зависимостей. При такой структуре невозможно создать сборку всего приложения в Visual Studio. Это делается непосредственно из TFS Team Build или MSBuild. На рис. 3.3 показан подход с использованием нескольких решений.


Рис. 3.3 Подход с использованием нескольких решений

Такая структура должна использоваться для очень больших приложений. Она поможет решить проблемы с производительностью и масштабируемостью Visual Studio IDE.
Одна из причин не использовать эту структуру – необходимость в сложном сценарии сборки, обеспечивающем обработку зависимостей составляющих решений через сборку решений в правильном порядке.


Рекомендации по работе над большим проектом

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

  1. Им нужна более сложная структура ветвления и слияния.
  2. Для них более высока вероятность работы с зависимостями между решениями и групповыми проектами.
  3. Для них более высока вероятность работы с несколькими сценариями сборки для компонентов и групп.

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

Заключение

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