Являются ли subversion externals антипаттернами? - PullRequest
68 голосов
/ 04 декабря 2008

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

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

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

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

Ответы [ 7 ]

70 голосов
/ 06 декабря 2008

Я являюсь автором цитаты в вопросе, которая пришла из предыдущего ответа .

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

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

65 голосов
/ 04 декабря 2008

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

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

19 голосов
/ 04 декабря 2008

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

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

18 голосов
/ 05 октября 2010

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

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

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

9 голосов
/ 06 декабря 2008

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

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

Внешнее определение - это сопоставление локального каталога с URL ** - и, возможно, с определенной версией - ** ресурса с контролем версий.

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

8 голосов
/ 06 декабря 2008

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

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

Меня тоже интересовали бы любые серьезные риски, связанные с этой договоренностью, и более эффективные подходы.

2 голосов
/ 06 декабря 2008

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

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

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

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

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

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

...