Являются ли субверсии внешними антипаттернами?

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

Хотя они кажутся идеальными для повторного использования библиотек и контроля версий поставщика программного обеспечения, они не без их критиков:

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

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

Ответ 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-сборкой. В долгосрочной перспективе я хотел бы включить основные концепции и функции в инструмент с открытым исходным кодом, который облегчает многоплатформенное решение.

Ответ 2

Я не думаю, что это анти-шаблон вообще. Я сделал несколько быстрых поисков в google и придумал в основном ничего... никто не жалуется, что использование svn: externals является плохим или вредным. Конечно, есть некоторые предостережения, о которых вы должны знать... и это не то, что вам нужно просто посыпать во все ваши репозитории... но что касается оригинальной цитаты, то только его личное (и субъективное) мнение, Он никогда не обсуждал svn: externals, кроме как осуждать их как анти-шаблон. Такие радикальные заявления без какой-либо поддержки или, по крайней мере, рассуждения о том, как человек пришел к заявлению, всегда подозреваются.

Тем не менее, есть некоторые проблемы с использованием внешних. Как ответил Майк, они могут быть очень полезны для указания на стабильные ветки выпущенного программного обеспечения... особенно программного обеспечения, которое вы уже контролируете. Мы используем их внутренне в ряде проектов для библиотек-утилит и т.д. У нас есть небольшая группа, которая расширяет и работает на базе библиотеки коммунальных услуг, но этот базовый код разделяется по нескольким проектам. Мы не хотим, чтобы разные команды просто проверяли код проекта полезности, и мы не хотим иметь дело с миллионом веток, поэтому для нас svn: externals работает очень хорошо. Для некоторых людей они не могут быть ответом. Однако я бы категорически не согласился с утверждением "Пожалуйста, не используйте..." и что эти инструменты представляют собой анти-шаблон.

Ответ 3

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

Лично я использую svn: externals, чтобы указать на "стабильные" ветки репозитория, которые у меня есть.

Ответ 4

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

Для некоторых наших внутренних библиотек, которые мы используем как внешние в наших проектах для конечных пользователей, я нашел полезным создать тег библиотеки в версии Major.Minor, где мы не применяем никаких изменений. С четырехточечной версией схемы (Major.Minor.BugFix.Build) мы разрешаем тегам поддерживать текущие изменения BugFix.Build(опять же, не нарушая никаких изменений). Это позволяет нам использовать внешнюю ссылку на тег без номера ревизии. В случае серьезных или других изменений прерывания создается новый тег.

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

Ответ 5

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

Выдержка из svn book:

Определение внешних символов - это отображение локального каталога в URL ** - и, возможно, конкретную ревизию - ** версии с версиями.

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

Ответ 6

Существуют определенные недостатки в внешних версиях subversion, но мы, похоже, разумно их используем для включения библиотек (как наших, так и вендоров), от которых зависит текущий проект. Поэтому я не рассматриваю их как "анти-шаблон". Важными моделями для меня являются:

  • Они указывают на конкретную ревизию или тег (никогда не голова) другого проекта.
  • Они вставляются в текущий проект вдали от собственного исходного кода и т.д. (например, в подкаталоге, называемом "файлы поддержки" ).
  • Они относятся только к файлам "интерфейса" других проектов (например, include folder) и бинарным библиотекам (т.е. мы не получаем полный источник другого проекта).

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

Ответ 7

Говоря, что a есть b, не делает a b, если вы не скажете, почему это так.

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

Внешние ссылки Subversion могут использоваться и злоупотреблять, а сама функция - не что иное, как функция. Нельзя сказать, что это образец, а не антипаттерн.

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

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

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