Comments 50
(Теги, конечно же, не читал, потому что их никто не читает)
Про надёжность того что вы там на удаляли я вообще молчу — зачем перекладывать бремя тестирования пакета на себя? Да и пулл реквест сделать уже будет проще.
Кстати, если композер у вас долго работает — возможно его стоит обновить? У меня он весьма быстр.
Если у вас проблема с композером — обновляйтесь пока ходите за чаем.
если же вы хотите обновляемый пакет
Я обычно хочу не обновляемый пакет, а надёжный — который с самого начала работал и будет и дальше предсказуемо работать, потому что в нём ничего не поменяется.
К слову, мой подход приводит к тому, что я иногда в оригинал этого же пакета пулл-реквесты отправляю — из-за того, что внимательно смотрю, что именно принимаю в кодовую базу и как оно работает. По-моему, всем от этого польза. :)
зачем перекладывать бремя тестирования пакета на себя?
Это вопрос надёжности ПО. У каждого свои критерии надёжности и того, сколько внимания он готов этому уделять. Есть примеры того, как откровенно вредный код может без вашего ведома подтянуться вместе с зависимостями. В общем-то, чем больше экономишь время, полагаясь на чужой код, который полагается на библиотеку, которая зависит от четвёртой библиотеки, тем выше риск получить нерабочий или уязвимый код.
Это всё не аксиома, и я не призываю фанатично чему-то следовать. Просто я вижу, что использование зависимостей может помогать тактически, но вредить стратегически.
Я просто верю, что стремление к надёжному и безопасному коду приводит в компанию людей, которым нужен надёжный и безопасный код, и которые готовы платить больше за твою внимательность в разработке.
Ну это пока пакет не обновляется а коллеги берут код с FTP
Я не совсем понимаю, причём тут FTP, если подключаемый код будет лежать в том же самом репозитории VCS. Я всегда считал, что FTP вместе с мамонтами вымер.
Я обычно хочу не обновляемый пакет, а надёжный — который с самого начала работал и будет и дальше предсказуемо работать, потому что в нём ничего не поменяется.
Зачем тогда вам "операции обновления зависимостей" при использовании composer? Загружайте точные версии, не запускайте composer update
, и всё.
Опять же, если вы фиксируете версию библиотеки, это совсем не значит, что её автор в этой версии зафиксировал зависимости от других библиотек на конкретных версиях, и лучше всё-таки регулярно запускать обновления, чтобы приходили обновления зависимостей второго-третьего-далее уровней, которые могут содержать
Лично для меня моя концепция лучше работает. Я её никому не навязываю. Она мне даёт больше плюсов, чем минусов.
придётся следить за развитием библиотеки в обход композера
А в чем разница с вашим подходом?
Но ведь и в вашем подходе можно пропустить какое-то обновление безопасности.
И если вижу ошибки, то я их могу мгновенно исправить
Если библиотека публично доступна и кто-то ей пользуется, значит в большинстве случаев она работает. Иначе зачем ее вообще добавлять в проект. Если встретилась какая-то редкая специфичная ошибка, и неохота ждать, можно унаследоваться и переопределить нужный метод. Вы будете "мгновенно" исправлять каждую ошибку в каждой библиотеке, и совокупное время уже сложно будет назвать мгновенным, а с возможностью обновления ошибки будут исправлены вообще без вашего участия.
Я, собственно, не вас пытаюсь переубедить, а скорее тех, кто прочитает диалог и узнает себя. В своих проектах можно делать как угодно, а рабочие потом придется кому-то поддерживать.
Я, собственно, не вас пытаюсь переубедить, а скорее тех, кто прочитает диалог и узнает себя. В своих проектах можно делать как угодно, а рабочие потом придется кому-то поддерживать.
Я, в общем-то, особенно тоже не убеждаю. Просто я вижу минусы и их озвучиваю. Кто-то видит минусы в моём подходе и тоже их озвучивает. Лично меня такие диалоги хорошо развивают и дают возможность переосмысливать собственные подходы к разработке.
Просто хорошо, когда есть разные точки зрения, и хорошо, когда видно и минусы и плюсы обеих этих точек зрения. Кто-то (включая меня) может увидеть все эти минусы и плюсы и изобрести третий вариант, который унаследует все плюсы.
Если встретилась какая-то редкая специфичная ошибка, и неохота ждать, можно унаследоваться и переопределить нужный метод. Вы будете «мгновенно» исправлять каждую ошибку в каждой библиотеке, и совокупное время уже сложно будет назвать мгновенным, а с возможностью обновления ошибки будут исправлены вообще без вашего участия
Конечно, можно отнаследоваться, но может получиться так, что, например, в классе, от которого я наследуюсь, статичный метод, который я хочу заменить, вызывается как
self::method()
, а не как static::method()
, и в результате вызовы пойдут мимо метода, который я пропатчил в дочернем классе. Придётся тогда и те куски кода тоже в дочернем классе переопределять. А это приведёт к тому, что я больше не буду вызывать часть оригинального кода. Если в эти части придут какие-то изменения, я ими не буду пользоваться, а они могут быть полезными, либо могут как-то значительно влиять на полезность других методов, которые я использую. Мне в таком случае придётся дополнительно следить за кодом, который приходит при обновлениях, чтобы соответственно реагировать в моём дочернем классе. Это снижает ценность подключения и обновления библиотеки в автоматическом режиме — тратится больше времени.Если в эти части придут какие-то изменения, я ими не буду пользоваться, а они могут быть полезными, либо могут как-то значительно влиять на полезность других методов, которые я использую. Мне в таком случае придётся дополнительно следить за кодом, который приходит при обновлениях
Зачем? Вот есть код, вы его скопировали и не обновляете. Вот есть тот же код, вы зафиксировали нужную версию в управлении пакетами и тоже не обновляете. Разницы нет, но во втором случае есть возможность обновить и проверить код автоматически, а в первом нет. Запустили тесты, все работает значит все ок, следить не надо. Тесты упали, значит либо откатили либо поправили пару мест, следить тоже не надо. А много мест быть не должно, потому что semver.
class ComposerLibDependency {
public static function usefulMethod($a, $b) {
return floor($a * $b);
}
}
class ComposerLib extends ComposerLibDependency {
public static function useMoreA($a, $b) {
return self::usefulMethod($a * 3, $b);
}
public static function useMoreB($a, $b) {
return self::usefulMethod($a, $b * 3);
}
}
class MyLibPatch extends ComposerLib {
public static function usefulMethod($a, $b) {
if (!is_numeric($a) || !is_numeric($b)) {
throw new Exception('Incorrect input');
}
return intval(parent::usefulMethod($a, $b));
}
}
var_dump(MyLibPatch::useMoreA(2, 3.5));
var_dump(MyLibPatch::useMoreB(2, 3.5));
Метод
MyLibPatch::usefulMethod()
здесь в итоге не используется. Чтобы этот мой фикс использовать, нужно заодно переопределить методы useMoreA
и useMoreB
, по сути, заменяя в них только self
на static
. Если потом в них придут изменения из ComposerLib
, они не отразятся, потому что я эти методы переопределил. Получается, мне нужно будет мониторить внешние зависимости, чтобы в эти переопределённые методы своевременно вносить изменения. Или, даже, если не вносить, то просто удостоверяться, что такое переопределение ничего не ломает в новых версиях билиотеки из композера.Это просто к вопросу об отнаследовании.
Если потом в них придут изменения из ComposerLib
Откуда там появятся изменения? Ни в скопированном коде, ни в фиксированной версии никаких изменений нет.
Если встретилась какая-то редкая специфичная ошибка, и неохота ждать, можно унаследоваться и переопределить нужный метод. Вы будете «мгновенно» исправлять каждую ошибку в каждой библиотеке, и совокупное время уже сложно будет назвать мгновенным, а с возможностью обновления ошибки будут исправлены вообще без вашего участия
Ключевые слова здесь: «а с возможностью обновления ошибки будут исправлены вообще без вашего участия».
Вы ничего про фиксированную версию не говорили в тот момент. Вы говорили про то, что подразумевается возможность обновления. То есть, вы советовали унаследоваться и переопределить метод, а потом спокойно дожидаться, пока придёт обновление. Я просто показываю минусы такого подхода.
При вашем подходе все равно придется следить за обновлением безопасности и фиксами ошибок (никто ведь не может быть уверен, что вы выкинули именно ту часть, которая эти ошибки содержит)
Ну и при подходе с композером никто не заставляет ждать цепочку "issue — fix — tag", всегда можете форкнуть и использовать форк до исправления ошибки.
Ну и при подходе с композером никто не заставляет ждать цепочку «issue — fix — tag», всегда можете форкнуть и использовать форк до исправления ошибки.
Минус в том, что форк придётся тоже поддерживать в актуальном состоянии. Нужно будет принимать из оригинала обновления. Иногда эти обновления будут затрагивать лично ваши изменения, не исправляя при этом ошибок, ради которых форк создавался, и придётся делать сложные мёржи.
Из того, всеми деталями чего не могу поделиться: фиксы в cordova-plugin-file-transfer, cordova-plugin-statusbar, react-dom.js (планирую попробовать отправить репорт и фикс, когда появится время, про ReactDOM.render, который возвращает не то, что должен, если вызывается внутри коллбека setState — нужно писать синтетический код для демонстрации — тот, который в проекте используется, показывать не могу), react-select.js (вообще выкинул после пары правок — проще и быстрее оказалось свою обёртку для <select> написать, чем натыкаться на постоянные грабли), sprintf.js (понимает %e, но не понимает %E + ещё несколько моментов, когда она работает не так, как в PHP).
Просто по поводу криткал-багов у меня такой подход, что проще бывает вообще не использовать библиотеку, чем заниматься правками критикал багов в ней. Поэтому я их не фиксю в других библиотеках и не могу похвалиться подобными правками. Мне хватило одного раза, когда я несколько лет назад работал с ics-parser на его начальных этапах жизни — правда, то, что я фиксил тогда, наружу никуда не выходило. Пишу свою библиотеку на эту тему, но она два года никуда не двигается, и я, наверное, не буду её писать всё-таки.
Сегодня ушло 20 секунд на то, чтобы Composer прочекал все зависимости, завтра ушло ещё 20 секунд.
А зачем вы вообще запускаете composer update, если вас устраивает версия, которая указана в composer.lock?
composer.json
прописываются, и чтобы autoload.php
и прочие сопутствующие загрузчики перегенерировались, нужно запускать composer update
Я видимо что-то не понимаю.
Очевидно же, что в библиотеке require
желательно оставить пустым, а в require-dev
пишем, что хотим, так как эти пакеты используются только для разработки и тестирования и к клиенту они не попадут.
В проекте же, в require
, можно вообще любые зависимости держать. За них отвечает команда разработчиков.
Проблема совмещения не совместимых пакетов мне вообще не понятна.
Зачем пытаться совместить несовместимое?
Если пакеты не совместимы, то просто не используйте их или выберете совместимую версию. В крайнем случае, всегда можно выбрать конкретный коммит в пакете. Да, выбрать конкретную версию зависимости у зависимости тоже можно.
А если хочется использовать фичу из последней версии пакета, которая не совместима с другими пакетами, то просто не используйте эту фичу. Подождите пока исправят совместить или сделайте PR.
Не стоит гнаться за последними релизами.
Мне бывает приходится использовать фиксированную версию пакетов, но только потому, что разработки ломают обратную совместимость.
Решение vendor in vendor мне видится странным и наверняка добавит проблем.
Не всегда всё так просто. Например, всё отлично работает на PHP5.6, приходит задача перевести всё на PHP7.1 по требованию аудитора/регулятора (альтернатива — закрыть бизнес) и выясняется, что две зависимости, которые отлично работали вместе под 5.6, несовместимы теми версиями с 7.1, а новые совместимые с 7.1 версии не работают вместе. Ну и PR могут не принимать месяцами или закрыть его вовсе с wantfix
Вариант в целом, более того лично так делал. Но не всегда легко взять и пофиксить, даже если в новой версии проблемы нет. очень сильно вникать в код библиотеки может понадобиться, особенно если это не лефтпад какой-нибудь, а ОРМ, например, или поддержка какого-то зубодробительного формата типа xls
Я сейчас перевожу один проект на PHP 7. Одн из пакетов оказался не совместим с PHP 7.
Так как проект заброшен, я просто взял и заменил его на другой. Переписал пару адаптеров и все.
Ну ещё немножко смазал маслицем чтоб лучше зашёл
Очевидно же, что в библиотеке require желательно оставить пустым, а в require-dev пишем, что хотим, так как эти пакеты используются только для разработки и тестирования и к клиенту они не попадут.
я правильно понимаю, что вы заставляете пользователя искать транзитивные зависимости вручную? ну типа у вас есть какой-нибудь api клиент с использованием guzzle, а guzzle нужной версии вы заставляете людей ставить?
А если ваша библиотека написана с использованием nullable, а у человека 7.0, он тоже об этом только опытным путем узнает?
1. у вас в src нигде не будет зависимости от guzzle, только от psr
2. в require у вас будет какой нибудь psr/http-message все равно, т.к он требуется для вашей библиотеки
Обычно я так и делаю. Один пакет чистый без зависимостей, а второй bundle для Symfony с конфигами и всеми делами.
Хочешь юзать в Symfony ставь бандл. Если у тебя не Symfony, юзай чистый пакет.
реквестят (мета)-пакет «some-vendor/my-super-interface-implementation»
этот пакет не зарегистрирован в packagist, но любой другой пакет (например из вашего списка саджестов) может прописать у себя provides some-vendor/my-super-interface-implementation
таким образом при установке будут разрешены все зависимости, не будет лишних реквайров, но при этом будет явное требование установить что-то что имплементит ваш интерфейс
Вот например так работают с тем же PSR-3 логгером
packagist.org/providers/psr/log-implementation
Прокси дело такое, сегодня он есть, а завтра его кто-то снёс, не поняв, что его основное назначение не ускорение доступа и т. п., а постоянное хранение. Или сам прокси оставят, а вот кэш почистят, когда место на диске кончится. Кэш же, не хранилище, прогреется со временем.
Вероятность значительно меньше. Те, в обязанности которых входит чистка, не будут разбираться, скорее всего, например, есть ли локальные патчи в каждом форке и вообще форк это или собственная наработка. Они и терминов таких могут не знать, но само слово "репозиторий" намекает, что там что-то важное хранится, а слова"кэширующий прокси" — что что-то временное.
Ну я сам не практикую тотальное форканье, но если апстрим не обновлялся годами, особенно с висящими пулл-реквестами от разных людей, то предпочитаю форкнуть сразу, будучи практически уверенным, что рано или поздно столкнусь с необходимостью патчить.
Именно. Но на самом деле мы лишь субъективно оценивали вероятности того, что в интересующей перспективе репозиторий может вообще исчезнуть. Если цена исчезновения очень высока, то нужно форкать всё, к какой бы бесконечно малой величине не стремилась оценка исчезновения или потери возможности доступа. Потери на поддержку форка без своих патчей (причём не обязательно до уровня каждого коммита или тега оперативно синкать, достаточно актуализировать на момент принятия решения об обновлении) могут оказаться пренебрежимо малы по сравнению с потенциальными потерями при недоступности.
От внезапного удаления пакета помогает во-первых все тот же кэш прокси (они все таки жалуются, когда пакет пропал при синке), а во вторых
--prefer-source
при разработке — хоть у кого то из разработчиков да останется пакет в исходном виде (если учесть, что он не обновляется).В самом крайнем случае код довольно легко извлечь с любого из стендов и уже в момент потери положить в репку, которую подключить в satis\toran\etc.
Мне все это кажется менее геморным, чем постоянно поддерживать несколько сотен форков, все таки пакеты не каждый день пропадают
Ключевое слово "кажется". Кому-то менее геморным кажется, кому-то более. Кто-то вообще не форкает без принятия решения развития своего форка, кто-то избранно, кто-то всё. В принципе, если создана масштабируемая инфраструктура для автоматического обновления хотя бы избранных, то цена форканья всех не столь уже высока.
Управление зависимостями в PHP