Я являюсь автором цитаты в вопросе, которая пришла из предыдущего ответа .
Джейсон вправе с подозрением относиться к таким кратким заявлениям, как мое, и просить объяснений. Конечно, если бы я полностью объяснил все в этом ответе, мне нужно было бы написать книгу.
Майк также прав, указывая на то, что одна из проблем с svn:external
-подобной функцией заключается в том, что изменения в целевом источнике могут нарушить ваш собственный источник, особенно если этот целевой источник находится в репозитории, которым вы не владеете .
Продолжая объяснение моего комментария, позвольте мне сначала сказать, что существуют "безопасные" способы использования svn:external
-подобной функции, как и с любым другим инструментом или функцией. Тем не менее, я называю его антипаттерном , потому что эта функция гораздо чаще используется не по назначению. По моему опыту, им всегда злоупотребляли, и я считаю, что вряд ли когда-либо буду использовать его таким безопасным образом и никогда не буду рекомендовать такое использование. Пожалуйста, обратите внимание, что я не имею в виду унижение команды Subversion - я люблю Subversion, хотя планирую перейти на базар.
Основная проблема с этой функцией заключается в том, что она поощряет и обычно используется для прямой связи источника одной сборки («проекта») с источником другой или для связи проекта с двоичным файлом (DLL, JAR, и т.д.) от которого это зависит. Ни одно из этих применений не является разумным, и они составляют антипаттерн.
Как я уже говорил в своем другом ответе, я считаю, что основным принципом для сборок программного обеспечения является то, что каждый проект создает точно ОДИН двоичный или первичный результат. Это можно считать применением принципа разделения интересов к процессу сборки. Это особенно верно в отношении одного проекта, непосредственно ссылающегося на источник другого, что также является нарушением принципа инкапсуляция . Другой формой нарушения такого рода является попытка создать иерархию сборки для построения всей системы или подсистемы путем рекурсивного вызова подкомпонов. Maven настоятельно рекомендует / обеспечивает такое поведение, что является одной из многих причин, по которым я его не рекомендую.
Наконец, я обнаружил, что существуют различные практические вопросы, которые делают эту функцию нежелательной. С одной стороны, svn:external
имеет некоторые интересные поведенческие характеристики (но подробности на данный момент меня избегают). С другой стороны, я всегда нахожу, что мне нужно, чтобы такие зависимости были явно видны моему проекту (процессу сборки), а не скрыты как метаданные управления исходным кодом.
Итак, что такое «безопасный» способ использования этой функции? Я бы посчитал, что это когда он временно используется только одним человеком, например, способ «настроить» рабочую среду. Я мог видеть, где программист может создать свою собственную папку в репозитории (или одну для каждого программиста), где они будут настраивать svn:external
ссылки на различные другие части репозитория, над которыми они в настоящее время работают. Затем проверка этой одной папки создаст рабочую копию всех их текущих проектов. Когда проект добавлен или завершен, определения svn:external
могут быть скорректированы, а рабочая копия обновлена соответствующим образом. Однако я предпочитаю подход, который не привязан к конкретной системе контроля версий, например, делать это с помощью скрипта, который вызывает извлечение.
Для справки, мое последнее знакомство с этой проблемой произошло летом 2008 года на клиенте-консультанте, который в массовом масштабе использовал svn:external
- ВСЁ было сшито для создания одной основной рабочей копии. Их основанные на Ant & Jython (для WebLogic) сценарии сборки были созданы поверх этой главной рабочей копии. Конечный результат: НИЧЕГО нельзя построить отдельно, было буквально десятки подпроектов, но ни один не был безопасен для самостоятельной проверки / работы. Поэтому любая работа в этой системе сначала требовала извлечения / обновления более 2 ГБ файлов (они также помещали двоичные файлы в хранилище). Выполнение чего-либо было бесполезным упражнением, и я ушел после трехмесячной попытки (было также много других антипаттернов).
РЕДАКТИРОВАТЬ: изложить на рекурсивных сборок -
За эти годы (особенно в последнее десятилетие) я построил огромные системы для компаний из списка Fortune 500 и крупных государственных учреждений, в которых участвуют многие десятки подпроектов, организованных в иерархии каталогов, которые имеют многоуровневую структуру. Я использовал проекты / решения Microsoft Visual Studio для организации систем на основе .NET, Ant или Maven 2 для систем на основе Java, и я начал использовать distutils и setuptools (easyinstall) для систем на основе Python. Эти системы также включают огромные базы данных, как правило, в Oracle или Microsoft SQL Server.
Я с большим успехом проектировал эти массивные сборки для простоты использования и повторяемости. Мой стандарт проектирования заключается в том, что новый разработчик может появиться в первый день, получить новую рабочую станцию (возможно, прямо от Dell с обычной установкой ОС), получить простой документ по установке (обычно всего одну страницу инструкций по установке), и быть в состоянии полностью настроить рабочую станцию и собрать всю систему из источника, без присмотра, без посторонней помощи и за полдня или меньше. Вызов самой сборки включает в себя открытие командной оболочки, переход в корневой каталог дерева исходных текстов и выполнение однострочной команды для сборки ВСЕГО.
Несмотря на этот успех, создание такой массивной системы сборки требует большой осторожности и строгого соблюдения принципов надежного проектирования, так же как и при создании массивного критически важного для бизнеса приложения / системы. Я обнаружил, что важной частью является то, что каждый проект (который производит один артефакт / результат) должен иметь один сценарий сборки, который должен иметь четко определенный интерфейс (команды для вызова частей процесса сборки), и он должен стоять один от всех других (под) проектов. Исторически сложилось так, что построить всю систему легко, но трудно / невозможно собрать только один элемент. Только недавно я научился тщательно следить за тем, чтобы каждый проект был по-настоящему самостоятельным.
На практике это означает, что должно быть как минимум два слоя сценариев сборки. Самый нижний уровень - это сценарии сборки проекта, которые создают каждый результат / артефакт. Каждый такой сценарий находится в корневом каталоге своего исходного дерева проекта (действительно, этот сценарий ОПРЕДЕЛЯЕТ свое исходное дерево проекта), эти сценарии ничего не знают об управлении исходным кодом, они ожидают запуска из командной строки, они ссылаются на все в проекте относительно к сценарию сборки, и они ссылаются на свои внешние зависимости (инструменты или двоичные артефакты, никакие другие исходные проекты) на основе нескольких настраиваемых параметров (переменных среды, файлов конфигурации и т. д.).
Второй уровень сценариев сборки также предназначен для вызова из командной строки, но они знают об управлении исходным кодом. Действительно, этот второй слой часто представляет собой один сценарий, который вызывается с именем проекта и версией, затем он проверяет источник для указанного проекта в новом временном каталоге (возможно, указанном в командной строке) и вызывает его сценарий сборки.
Возможно, потребуется больше вариантов для размещения серверов непрерывной интеграции, нескольких платформ и различных сценариев выпуска.
Иногда возникает необходимость в третьем слое скриптов, который вызывает второй слой скриптов (который вызывает первый слой) с целью создания определенных подмножеств общего набора проекта. Например, у каждого разработчика может быть свой сценарий, который создает проекты, над которыми они работают сегодня. Может существовать сценарий для сборки всего, чтобы генерировать основную документацию или рассчитывать метрики.
Несмотря на это, я обнаружил, что попытка трактовать систему как иерархию проектов контрпродуктивна. Он связывает проекты друг с другом, так что они не могут быть свободно собраны отдельно, или в произвольных местоположениях (временный каталог на сервере непрерывной интеграции), или в произвольном порядке (при условии, что зависимости удовлетворены). Зачастую попытка форсировать иерархию нарушает любую интеграцию IDE, которую можно попытаться сделать.
Наконец, создание массивной иерархии проектов может быть просто слишком интенсивным. Например, весной 2007 года я попытался создать скромную исходную иерархию (Java плюс Oracle), построенную с использованием Ant, которая в итоге завершилась неудачей, поскольку сборка всегда прерывалась с Java OutOfMemoryException. Это было на рабочей станции ОЗУ 2 ГБ с 3,5 ГБ подкачки, для которой я настроил JVM, чтобы иметь возможность использовать всю доступную память. Приложение / система были относительно тривиальными с точки зрения количества кода, но рекурсивные вызовы сборки в конечном итоге исчерпали память, независимо от того, сколько памяти я ей выделил. Конечно, выполнение также занимало целую вечность (30-60 минут было обычным делом, прежде чем оно прерывалось). Я знаю, как ОЧЕНЬ хорошо настроить, но в конечном итоге я просто превысил пределы инструментов (в данном случае Java / Ant).
Так что сделайте себе одолжение, постройте свою сборку как отдельные проекты, а затем соберите их в полную систему. Держите это легким и гибким. Наслаждайтесь.
РЕДАКТИРОВАТЬ: Больше на antipatterns
Строго говоря, антипаттерн - это распространенное решение, которое выглядит так, как будто оно решает проблему, но не делает этого, либо потому, что оставляет важные пробелы, либо потому, что создает дополнительные проблемы (часто хуже, чем первоначальная проблема). Решение обязательно включает в себя один или несколько инструментов плюс методику их применения к рассматриваемой проблеме. Таким образом, называть антипаттерном инструмент или определенную особенность инструмента довольно сложно, и кажется, что люди обнаруживают его и реагируют на него - достаточно справедливо.
С другой стороны, поскольку в нашей отрасли, как представляется, принято концентрировать внимание на инструментах, а не на технике, внимание уделяется именно инструментам / функциям (случайный обзор вопросов здесь на StackOverflow, кажется, легко иллюстрирует) , Мои комментарии и сам этот вопрос отражают эту практику.
Однако иногда кажется особенно оправданным делать такое растяжение, как в этом случае. Некоторые инструменты, кажется, «ведут» пользователя к конкретным методам их применения, и некоторые утверждают, что инструменты формируют мысль (слегка перефразировано). В основном именно в этом духе я предполагаю, что svn:external
является антипаттерном.
Чтобы более точно сформулировать проблему, антипаттерн должен спроектировать решение для сборки, которое включает в себя связывание проектов вместе на исходном уровне, или неявно версионировать зависимости между проектами, или позволить таким зависимостям неявно измениться, потому что каждый из них вызывает очень негативные последствия. Характер svn:external
-подобной функции делает очень трудным избежать этих негативных последствий.
Правильная обработка зависимостей между проектами включает рассмотрение этой динамики наряду с базовой проблемой, а инструменты и методы ведут по другому пути. Примером, который следует рассмотреть, является Ivy , который помогает способом, подобным Maven, но без многих недостатков. Я исследую Ivy в сочетании с Ant как свое краткосрочное решение проблемы сборки Java. В долгосрочной перспективе я хочу включить основные концепции и функции в инструмент с открытым исходным кодом, который облегчает многоплатформенное решение.