Ответ 1
Я автор цитаты в вопросе, который пришел из предыдущего ответа.
Джейсон прав, чтобы быть подозрительным к кратким заявлениям, таким как мой, и попросить объяснения. Конечно, если бы я полностью объяснил все в этом ответе, мне нужно было бы написать книгу.
Майк также имеет право указать, что одна из проблем с svn:external
-подобной особенностью заключается в том, что изменения в целевом источнике могут разорвать ваш собственный источник, особенно если этот целевой источник находится в репозитории, который у вас нет..
В дальнейшем объясняя мой комментарий, позвольте мне сначала сказать, что есть "безопасные" способы использования функции svn:external
, как и для любого другого инструмента или функции. Тем не менее, я называю это antipattern, потому что эта функция гораздо более подвержена неправильному использованию. По моему опыту, это всегда было неправильно использовано, и я нахожусь очень маловероятным, чтобы когда-либо использовать его таким безопасным образом и никогда не рекомендовал использовать его. Пожалуйста, примите к сведению, что я имею в виду отсутствие унижения в команде Subversion - я люблю Subversion, хотя я планирую перейти на Bazaar.
Основная проблема с этой функцией заключается в том, что она поощряется и обычно используется для непосредственного связывания источника одной сборки ( "проекта" ) с источником другого или для связывания проекта с двоичным (DLL, JAR, и т.д.), от которых это зависит. Ни одно из этих применений не является мудрым, и они составляют антипаттерн.
Как я уже сказал в своем другом ответе, я считаю, что важным принципом для сборки программного обеспечения является то, что каждый проект строит ровно один бинарный или основной результат. Это можно рассматривать как применение принципа разделения проблем на процесс сборки. Это особенно верно в отношении одного проекта, непосредственно ссылающегося на источник другого, что также является нарушением принципа encapsulation. Другой формой такого нарушения является попытка создать иерархию построения для построения всей системы или подсистемы путем рекурсивного вызова подстроек. Maven настоятельно рекомендует/применяет это поведение, что является одной из многих причин, по которым я не рекомендую.
Наконец, я обнаружил, что существуют различные практические вопросы, которые делают эту функцию нежелательной. Во-первых, svn:external
обладает некоторыми интересными поведенческими характеристиками (но на данный момент подробности уходят от меня). Для другого я всегда считаю, что мне нужны такие зависимости, чтобы они были явным образом видны моему проекту (процесс сборки), а не были захоронены как некоторые метаданные управления версиями.
Итак, что такое "безопасный" способ использования этой функции? Я бы подумал, что это когда оно используется временно одним человеком, например, способом "настроить" рабочую среду. Я мог видеть, где программист может создать свою собственную папку в репозитории (или по одному для каждого программиста), где они будут настраивать ссылки svn:external
на другие другие части репозитория, над которыми они в настоящее время работают. Затем проверка этой папки создаст рабочую копию всех текущих проектов. Когда проект будет добавлен или закончен, определения svn:external
могут быть скорректированы и рабочая копия будет обновлена соответствующим образом. Тем не менее, я предпочитаю подход, который не привязан к конкретной системе управления версиями, например, с помощью script, который вызывает проверки.
Для записи моя самая недавняя публикация этой проблемы произошла летом 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 с обычной типичной установкой ОС), получить простой установочный документ (обычно только одну страницу инструкций по установке) и иметь возможность полностью настроить рабочую станцию и построить полную систему из источника, без присмотра, без помощи и через полдня или меньше. Вызов самой сборки предполагает открытие командной оболочки, переход в корневую директорию исходного дерева и выдачу однострочной команды для построения ВСЕГО.
Несмотря на этот успех, построение такой массивной системы сборки требует большой осторожности и строгого соблюдения принципов твердого дизайна, как и при создании массивного критически важного для бизнеса приложения/системы. Я обнаружил, что важная часть состоит в том, что каждый проект (который создает один артефакт/поставляемый) должен иметь единую конструкцию script, которая должна иметь четко определенный интерфейс (команды для вызова частей процесса сборки), и это должен стоять отдельно от всех других (суб) проектов. Исторически, легко построить всю систему, но трудно/невозможно построить только одну часть. Только недавно я научился тщательно следить за тем, чтобы каждый проект действительно стоял один.
На практике это означает, что должно быть не менее двух уровней скриптов сборки. Самый низкий уровень - скрипты построения проекта, которые производят каждый поставляемый/артефакт. Каждый такой script находится в корневом каталоге своего дерева исходных текстов проекта (действительно, этот script ОПРЕДЕЛЕТ его дерево исходных текстов проекта), эти скрипты ничего не знают об управлении версиями, они ожидают, что они будут запущены из командной строки, они ссылаются на все в проекте относительно сборки script, и они ссылаются на свои внешние зависимости (инструменты или двоичные артефакты, другие проекты-источники) на основе нескольких настраиваемых параметров (переменные среды, файлы конфигурации и т.д.).
Второй слой скриптов сборки также предназначен для вызова из командной строки, но они знают об управлении источником. Действительно, этот второй уровень часто представляет собой единственный script, который вызывается с именем проекта и версией, затем проверяет источник для именованного проекта на новый временный каталог (возможно, указанный в командной строке) и вызывает его сборку script.
Возможно, потребуется больше вариантов для размещения серверов непрерывной интеграции, нескольких платформ и различных сценариев выпуска.
Иногда возникает потребность в третьем уровне скриптов, который вызывает второй уровень скриптов (которые вызывают первый уровень) с целью создания определенных подмножеств общего набора проектов. Например, у каждого разработчика может быть свой собственный script, который строит проекты, над которыми они работают сегодня. Может существовать script для создания всего, чтобы генерировать основную документацию или вычислять показатели.
Несмотря на это, я обнаружил, что попытка рассматривать систему как иерархию проектов контрпродуктивна. Он связывает проекты друг с другом, чтобы они не могли быть построены отдельно или в произвольных местах (временный каталог на сервере непрерывной интеграции) или в произвольном порядке (при условии, что зависимости выполнены). Часто попытка заставить иерархию нарушает любую интеграцию IDE, которую можно попытаться выполнить.
Наконец, создание массивной иерархии проектов может быть просто слишком интенсивным. Например, во время spring в 2007 году я попытался создать скромную исходную иерархию (Java плюс Oracle), которую я создал с помощью Ant, что в конечном итоге потерпело неудачу, потому что сборка всегда прерывалась с помощью исключения Java OutOfMemoryException. Это было на рабочей станции объемом 2 ГБ с пространством подкачки на 3,5 ГБ, для которого я настроил JVM, чтобы иметь возможность использовать всю доступную память. Приложение/система была относительно тривиальной с точки зрения количества кода, но вызовы рекурсивной сборки в конечном итоге исчерпали память, независимо от того, сколько памяти я ей дал. Конечно, это также потребовалось навсегда, чтобы выполнить (30-60 минут было обычным, прежде чем он прервался). Я знаю, как настроить ОЧЕНЬ хорошо, но в конечном итоге я просто превышал пределы инструментов (Java/Ant в этом случае).
Итак, сделайте себе одолжение, постройте свою сборку как самостоятельные проекты, а затем составьте их в полную систему. Держите его легким и гибким. Наслаждайтесь.
РЕДАКТИРОВАТЬ: Больше о антипаттернах
Строго говоря, антипаттерн - это общее решение, похожее на то, что оно решает проблему, но не потому, что оно оставляет важные пробелы или потому, что оно вводит дополнительные проблемы (часто хуже исходной проблемы). Решение обязательно включает в себя один или несколько инструментов плюс метод их применения к проблеме. Таким образом, это растягивание, чтобы ссылаться на инструмент или конкретную особенность инструмента как антипаттерн, и кажется, что люди обнаруживают и реагируют на это растяжение - достаточно справедливо.
С другой стороны, поскольку, как представляется, обычной практикой в нашей отрасли является фокусирование на инструментах, а не на технике, это инструмент/функция, которая привлекает внимание (случайный обзор вопросов здесь, на StackOverflow, кажется, легко иллюстрирует), Мои комментарии и сам этот вопрос отражают эту практику.
Однако иногда кажется особенно оправданным сделать это растяжение, например, в этом случае. Некоторые инструменты, похоже, "приводят" пользователя к конкретным методам их применения, до того момента, когда некоторые утверждают, что инструменты формы мысли (слегка перефразированы), В основном в этом духе я предлагаю, чтобы svn:external
был антипаттерном.
Чтобы более точно сформулировать проблему, антипаттерн должен разработать решение для сборки, которое включает в себя объединение проектов на исходном уровне или неявное изменение зависимостей между проектами или разрешение таких зависимостей на неявное изменение, поскольку каждый из этих вызывает очень негативные последствия. Характер svn:external
-полюбия позволяет избежать этих негативных последствий очень сложно.
Правильная обработка зависимостей между проектами предполагает устранение этой динамики наряду с базовой проблемой, а инструменты и методы ведут по другому пути. Примером, который следует учитывать, является Ivy, который помогает в манере, подобной Maven, но без многих недостатков. Я изучаю Ivy в сочетании с Ant, как свое краткосрочное решение проблемы с Java-сборкой. В долгосрочной перспективе я хотел бы включить основные концепции и функции в инструмент с открытым исходным кодом, который облегчает многоплатформенное решение.