Предполагаю, что если бы дизайн языка писали сегодня, сделали бы два разных оператора == и ===. Тройное равенство было бы сравнением identity, а двойное - неявный вызов null-safe Objects.equals, на уровне исходного кода естественно запрещающий сравнение объектов, которые не могут быть приведены друг к другу. Тогда бы и не было известной проблемы со сравнением Integer.valueOf(128).
Сейчас это уже невозможно, т.к. пришлось бы переопределить поведение именно ==, а делать наоборот очевидно бессмысленно.
Тут проблема в другом - как это вписать в язык и платформу, которым в этом году исполняется 30 лет, не нарушив обратную совместимость и соблюдая принятые в языке конвенции. .net появился на 10 лет позже и очевидно учел в т.ч. опыт java, плюс на тот момент не было проблемы не сломать существующий код
Насчет скорости Maven согласен с Вами. Порой компиляция проекта на maven быстрее, чем reimport (или фаза конфигурации) Gradle. Но когда дело доходит до оптимизации тестов (кещи и пр.) - компромисс становится сложнее.
Не рассматривали вариант переезда на Gradle? Maven хорош, но когда нужна подобная кастомизация, иногда проще перейти на другую систему сборки чем делать кастом (который потом не дружит с IDE и пр.)
Поэтому команда Valhalla сформулировала определенные требования по присвоению значения, которые говорят, что необходимо присваивать эти значения перед вызовом конструктора суперкласса.
Если не ошибаюсь, это было запрещено на уровне исходного кода (до вызова super-конструктора), но в байт-коде можно выполнять подобные операции при обязательном условии вызова super-конструктора до выхода из самого конструктора (и такой класс успешно пройдет загрузку и валидацию). Т.е. такой фокус можно провернуть с помощью генеренного байт-кода, если очень нужно.
По поводу поделиться с Apache - мне не жалко (код выше под лицензией Apache 2.0). Только нет уверенности, что это попадает в их планы. Я смотрел несколько видео и читал статьи от мейнтейнеров проекта и насколько понял, они очень сильно заморочены на обратную совместимость. С одной стороны это хорошо, с другой - это существенно ограничивает потенциальное развитие проекта. В конце концов, Maven - это инструмент, а не язык программирования, поэтому ломающие изменения здесь могли бы быть ок (а иначе зачем обновляться?). Для сравнения Gradle регулярно ломает совместимость своих API, но делают они это весьма аккуратно, заблаговременно объявляя API устаревшими, давая понятную диагностику и пр. И их инструмент активно развивается.
При возможности думаю поделиться своими идеями с мейнтейнерами Maven (либо письмом, либо где-нибудь на конференции).
Проводили сравнение по скорости Gradle Cache (Develocity) и Maven Cache?
Нет, но предположу что для билда, где все таски берутся из кеша результат будет примерно одинаковый.
есть пример проекта большого размера где бы он плохо работал?
Здесь я еще раз заострю внимание на том, что дело по сути не в размере, а в том что проект большего размера с большей вероятностью будет иметь кастомизацию. Отвечая на вопрос - да, есть пример такого проекта. Там из-за большого количества интеграционные тесты были разделены на группы и выполнялись в отдельных джобах. При этом компилировалось всё один раз на первом шаге (mvn clean package -DskipTests=true), и передавалось на следующий этап в параллельные пайплайны (mvn failsafe:integration-test failsafe:verify -Dit.test=$TEST_FILTER_1 где TEST_FILTER_1 - N разных фильтров тестов), так экономили на компиляции. С apache build cache возникло несколько проблем:
он работает только с циклами lifecycle, а не goal. Т.е. указывать goal нельзя failsafe:integration-test, можно например так: mvn verify, но тогда Maven будет прогонять все шаги включая компиляцию (в теории ее наверно можно отключить через skip compile plugin; но это не единственная проблема)
оказалось достаточно проблематично подобрать такую конфигурацию extension, чтобы всё правильно кешировалось. Т.е. легко допустить ошибку, при которой кешируется пустой результат запуска тестов и потом ошибочно берется из кеша даже при других параметрах
Думаю, в целом можно настроить extension, поэтому я и рекомендовал его посмотреть. В нашем случае пока разбирались в коде apache build cache extension (который весьма компактный проект), написали свой собственный, т.к. в любом случае нужны были доработки вроде дополнительной мета-информации, сбор метрик и пр.
Полностью солидарен с автором. В любых священных войнах по поводу выбора технологии или фреймворка - я на стороне консистентности, даже если выбор не мой личный фаворит. В долгосроке разобравшись с тонкими нюансами существующего решения его можно переписать на новое или использовать классический популярный фреймворк (желательно одним махом или за короткий срок, чтобы не создавать риск параллельно существующих решений). Но этим не должны заниматься люди с порога, потому что в большинстве случаев это все уйдет не дальше прототипов, которые будут бельмом выбиваться из общей канвы.
Еще понравилось это предложение
Я видел примеры успешного разбиения крупных кодовых баз, но никогда не было так, чтобы этим занималась команда, ещё не освоившая в совершенстве выпуск фич внутри этих кодовых баз.
Действительно, в команды платформы, которые делают общий код и модуляризацию нужно либо переходить из фиче-команд, либо в случае внешнего найма работа в компании должна начинаться с онбординга в фиче-команде хотя бы месяц-два. Иначе, какой бы не был крутой опыт и бэкграунд, неверных доводов о текущей ситуации не избежать.
Я был в курсе о кончине основателя Флибусты, об этом много писали. Но то, что это тот же самый Stiver, с которым я вел переписку насчет Fernflower в 2014 году - это неожиданный поворот. Многогранная была личность. Очень жаль.
Если не запускать кодогенерацию, IntellijIDEA подсветит часть файлов проекта красным.
Знакомая проблема. Что думаете насчет добавления генеренного кода в git-репо (тогда и при смене веток генеренный код соответственно переключался)? Я поначалу был категорично настроен по отношению к этой идее, но на практике оказалось весьма неплохо в т.ч. и потому, что это позволяло видеть изменения в истории не только в исходниках кодогенерации (вроде proto-файлов или SQL-миграций), но и в генеренном коде. Тут, конечно, это не для всех случаев подойдет, но для многих - как минимум, это позволит делать компиляцию средствами IDE без необходимости делегирования в build-систему. А это, между прочим, означает эффективную инкрементную сборку. Проще и быстрее. Тема дискуссионная и здесь, конечно, есть подводные камни.
Это происходит так: бежишь глазами по табло по отсортированному времени, зная время и город назначения. Находишь нужную строчку и идешь в гейт. Там перепроверяешь время вылета и город на экране (ведь типа весь такой предусмотрительный). Но не номер рейса, т.к. интуитивно не предполагаешь (не предполагал раньше) такой подставы. И спокойно ждешь до последнего момента. Билет корпоративный, поэтому на такие детали как авиакомпания и прочее почти не обращаешь внимания.
У меня была другая история. Вылетал из Схипхол (Амстердам), было два рейса одновременно на Варшаву. Мало того, что кто-то додумался их поставить в одно и то же время, так они были в разных гейтах (а аэропорт достаточно большой) и на табло был отображен только один. Попался на этот косяк не только я - в итоге еле успел. Теперь всегда помимо времени вылета проверяю на табло еще и номер рейса.
У меня была другая история. Вылетал из Схипхол (Амстердам), было два рейса одновременно на Прагу. Мало того, что кто-то додумался их поставить в одно и то же время, так они были в разных гейтах и на табло был отображен только один. Попался на этот косяк не только я - в итоге еле успел. Теперь всегда помимо времени вылета проверяю на табло еще и номер рейса.
Предполагаю, что если бы дизайн языка писали сегодня, сделали бы два разных оператора
==
и===
. Тройное равенство было бы сравнением identity, а двойное - неявный вызов null-safeObjects.equals
, на уровне исходного кода естественно запрещающий сравнение объектов, которые не могут быть приведены друг к другу. Тогда бы и не было известной проблемы со сравнениемInteger.valueOf(128)
.Сейчас это уже невозможно, т.к. пришлось бы переопределить поведение именно
==
, а делать наоборот очевидно бессмысленно.Тут проблема в другом - как это вписать в язык и платформу, которым в этом году исполняется 30 лет, не нарушив обратную совместимость и соблюдая принятые в языке конвенции.
.net появился на 10 лет позже и очевидно учел в т.ч. опыт java, плюс на тот момент не было проблемы не сломать существующий код
Насчет скорости Maven согласен с Вами. Порой компиляция проекта на maven быстрее, чем reimport (или фаза конфигурации) Gradle.
Но когда дело доходит до оптимизации тестов (кещи и пр.) - компромисс становится сложнее.
Не рассматривали вариант переезда на Gradle? Maven хорош, но когда нужна подобная кастомизация, иногда проще перейти на другую систему сборки чем делать кастом (который потом не дружит с IDE и пр.)
Если не ошибаюсь, это было запрещено на уровне исходного кода (до вызова super-конструктора), но в байт-коде можно выполнять подобные операции при обязательном условии вызова super-конструктора до выхода из самого конструктора (и такой класс успешно пройдет загрузку и валидацию). Т.е. такой фокус можно провернуть с помощью генеренного байт-кода, если очень нужно.
Обратная совместимость, пожалуй, одна из главных причин успеха Java как платформы.
Спасибо за статью. Маленькое замечание
Технически, в ArrayList всегда создается Object[], т.к. невозможно создать массив по generic-типу.
Плагины с поддержкой кеширования: https://github.com/seregamorph/maven-surefire-cached
Прототип переписанного планировщика с улучшенным параллелизмом: https://github.com/seregamorph/maven-surefire-cached/pull/3 - это изменение по сути подразумевает слом обратной совместимости из-за очередности фаз сборки
По поводу поделиться с Apache - мне не жалко (код выше под лицензией Apache 2.0). Только нет уверенности, что это попадает в их планы. Я смотрел несколько видео и читал статьи от мейнтейнеров проекта и насколько понял, они очень сильно заморочены на обратную совместимость. С одной стороны это хорошо, с другой - это существенно ограничивает потенциальное развитие проекта. В конце концов, Maven - это инструмент, а не язык программирования, поэтому ломающие изменения здесь могли бы быть ок (а иначе зачем обновляться?). Для сравнения Gradle регулярно ломает совместимость своих API, но делают они это весьма аккуратно, заблаговременно объявляя API устаревшими, давая понятную диагностику и пр. И их инструмент активно развивается.
При возможности думаю поделиться своими идеями с мейнтейнерами Maven (либо письмом, либо где-нибудь на конференции).
Нет, но предположу что для билда, где все таски берутся из кеша результат будет примерно одинаковый.
Здесь я еще раз заострю внимание на том, что дело по сути не в размере, а в том что проект большего размера с большей вероятностью будет иметь кастомизацию. Отвечая на вопрос - да, есть пример такого проекта. Там из-за большого количества интеграционные тесты были разделены на группы и выполнялись в отдельных джобах. При этом компилировалось всё один раз на первом шаге (
mvn clean package -DskipTests=true
), и передавалось на следующий этап в параллельные пайплайны (mvn failsafe:integration-test failsafe:verify -Dit.test=$TEST_FILTER_1
гдеTEST_FILTER_1
- N разных фильтров тестов), так экономили на компиляции. С apache build cache возникло несколько проблем:он работает только с циклами lifecycle, а не goal. Т.е. указывать goal нельзя
failsafe:integration-test
, можно например так:mvn verify
, но тогда Maven будет прогонять все шаги включая компиляцию (в теории ее наверно можно отключить через skip compile plugin; но это не единственная проблема)оказалось достаточно проблематично подобрать такую конфигурацию extension, чтобы всё правильно кешировалось. Т.е. легко допустить ошибку, при которой кешируется пустой результат запуска тестов и потом ошибочно берется из кеша даже при других параметрах
Думаю, в целом можно настроить extension, поэтому я и рекомендовал его посмотреть. В нашем случае пока разбирались в коде apache build cache extension (который весьма компактный проект), написали свой собственный, т.к. в любом случае нужны были доработки вроде дополнительной мета-информации, сбор метрик и пр.
Полностью солидарен с автором. В любых священных войнах по поводу выбора технологии или фреймворка - я на стороне консистентности, даже если выбор не мой личный фаворит. В долгосроке разобравшись с тонкими нюансами существующего решения его можно переписать на новое или использовать классический популярный фреймворк (желательно одним махом или за короткий срок, чтобы не создавать риск параллельно существующих решений). Но этим не должны заниматься люди с порога, потому что в большинстве случаев это все уйдет не дальше прототипов, которые будут бельмом выбиваться из общей канвы.
Еще понравилось это предложение
Действительно, в команды платформы, которые делают общий код и модуляризацию нужно либо переходить из фиче-команд, либо в случае внешнего найма работа в компании должна начинаться с онбординга в фиче-команде хотя бы месяц-два. Иначе, какой бы не был крутой опыт и бэкграунд, неверных доводов о текущей ситуации не избежать.
Перешли сразу с 2.7 на 3.3? Если так, то почему решили пропустить 3.0?
Я был в курсе о кончине основателя Флибусты, об этом много писали.
Но то, что это тот же самый Stiver, с которым я вел переписку насчет Fernflower в 2014 году - это неожиданный поворот. Многогранная была личность. Очень жаль.
Упоминание книги в Угол-шоу Игоря Угольникова
https://youtu.be/ooS4HdP2lAQ?si=tGBJ8_HLyEGLABBh&t=182
Я видел сотрудницу HR, которая перешла в системную аналитику. Всякое бывает
Знакомая проблема. Что думаете насчет добавления генеренного кода в git-репо (тогда и при смене веток генеренный код соответственно переключался)?
Я поначалу был категорично настроен по отношению к этой идее, но на практике оказалось весьма неплохо в т.ч. и потому, что это позволяло видеть изменения в истории не только в исходниках кодогенерации (вроде proto-файлов или SQL-миграций), но и в генеренном коде. Тут, конечно, это не для всех случаев подойдет, но для многих - как минимум, это позволит делать компиляцию средствами IDE без необходимости делегирования в build-систему. А это, между прочим, означает эффективную инкрементную сборку. Проще и быстрее.
Тема дискуссионная и здесь, конечно, есть подводные камни.
Ну так статья про "чтобы найти работу", а не построить успешную карьеру.
Это происходит так: бежишь глазами по табло по отсортированному времени, зная время и город назначения. Находишь нужную строчку и идешь в гейт. Там перепроверяешь время вылета и город на экране (ведь типа весь такой предусмотрительный). Но не номер рейса, т.к. интуитивно не предполагаешь (не предполагал раньше) такой подставы. И спокойно ждешь до последнего момента.
Билет корпоративный, поэтому на такие детали как авиакомпания и прочее почти не обращаешь внимания.
У меня была другая история. Вылетал из Схипхол (Амстердам), было два рейса одновременно на Варшаву. Мало того, что кто-то додумался их поставить в одно и то же время, так они были в разных гейтах (а аэропорт достаточно большой) и на табло был отображен только один. Попался на этот косяк не только я - в итоге еле успел. Теперь всегда помимо времени вылета проверяю на табло еще и номер рейса.
У меня была другая история. Вылетал из Схипхол (Амстердам), было два рейса одновременно на Прагу. Мало того, что кто-то додумался их поставить в одно и то же время, так они были в разных гейтах и на табло был отображен только один. Попался на этот косяк не только я - в итоге еле успел. Теперь всегда помимо времени вылета проверяю на табло еще и номер рейса.
Это же было 100 тысяч попыток машинного обучения, ведь да? ?