Как стать автором
Обновить
45
0
Артем Навроцкий @Bozaro

Программист

Отправить сообщение

Тут не задан самый главный вопрос: "Зачем нужна эта картина? Какая задача решается?"

C git'ом кстати тоже есть проблема, он хорошо подходит для сорцов, а вот что делать с гигабайтными текстурами или файлами модели по 100мб, или луашником/json'ом уровня размером под 20-30 мб текста? Тут либо держишь 2 cvs - одну для сорцов, вторую для контента, либо пишешь своё решение.

Большие файлы стало можно использовать после появления Git LFS.

А проблему взаимодействия Git с не-программистами мы решали реализацией Subversion API поверх Git-репозитория: https://habr.com/ru/companies/vk/articles/241095/

Для совсем мелких проектов подходит почти всё, что угодно.

Проблемы начинаются когда увеличивается количество хотелок:

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

  • Хочется иметь хоть какую-то статистику по тестам (тут с ностальгией вспоминаю TeamCity);

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

  • Хочется иметь нотификации авторам о падении тестов;

  • Хочется иметь интеграцию с системой контроля версий;

  • Хочется иметь возможность как-то управлять секретами;

  • Хочется иметь возможность делать цепочки сборок;

  • И т.д. и т.п.

При этом основные проблемы визуализации возникают в негативном сценарии: пока всё работает, оно никому не интересно. А вот возможность по выводу понять, что и где пошло не так, очень полезна.

Проблему безопасности можно частично решить через вынос общих запчастей в отдельную "доверенную" Jenkins Shared Library. Тогда на её код в src не будут распространяться ограничения песочницы, хотя на vars - всё ещё будут.

На счет плагинов я с Вами согланен: в Jenkins безумное количество legacy и очень разное качество кода от плагина к плагину.

Ну и отдельная проблема в том, что там модульность доведена до абсурда: обычно функционал затрагивает сразу несколько плагинов и не всегда очевидно, какой именно за какую часть фичи отвечает.

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

Ну и декларативный pipeline в Jenkins то еще поделие: это де-факто инструкция императивного pipeline, то есть всё равно нельзя сказать, что сделает pipeline не выполнив его.

Из-за этого, в частности:

  • вечно поломанная визуализация сборки;

  • объявления параметров и опций в pipeline влияет на следующую, а не на текущую сборку.

Когда речь заходит про CI, я всё время вспоминаю цитату из Симпсонов:

> Check out The Willie World News! I reviewed the new tractors! They're all shite!

Выбор CI выглядит как поиск наименее плохого варианта :(

Я не знаю СУБД, которые полностью поддерживающая весь ansi.

Но UPDATE входит в Core SQL Features под номером E101-03. Всё-таки весь стандарт и его Core SQL часть несколько разные вещи :)

С моей точки зрения, SQL СУБД должна соответствовать хоть одному SQL-стандарту.
Должен быть не только похожий синтаксис, но и поведение.

К примеру, запрос:

UPDATE foo SET a = b, b = a WHERE  id = 42

должен внутри выражений брать значения исходного кортежа, то есть поменять значения полей a и bместами. В MySQL же в обе колонки попадёт исходное значение b.

Про особенное виденье уровней изоляции транзакций уже было выше.

Все эти особенности в MySQL документированы и переведены в категорию фичей, но от этого как-то не легче.

MySQL - это минное поле. У неё куча очень странных особенностей, которые могут вставить нож в спину в самый неожиданный момент.
Из особо прекрасного: https://www.percona.com/blog/what-if-mysqls-repeatable-reads-cause-you-to-lose-money/
Ну и, строго говоря, MySQL не является SQL СУБД.

Вы не представляете масштаб проблемы: распил проекта на маленькие модули требует годы.

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

К тому же сокращение времени на итерацию в CI делает рефакторинг заметно комфортнее.

Распилить проект и уменьшить связанность кода это благая цель.
Но в данном случае:

  • уменьшение связанности никак не конфликтует с оптимизацией инструментария сборки;

  • уменьшение связанности кода никак нельзя назвать "простым" процессом.

"Монолит" это что?

Я так и не смог понять, как подружить IDE и Bazel...

Собственно из-за этого и пошли по пути, когда BUILD-файлы генерируются на базе исходного кода и go.mod-файлов, максимально повторяя go build-сборку.

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

Эта схема оказалась на удивление удачной:

  • разработчикам не нужно воевать с Bazel;

  • IDE работает как работало;

  • генераторы получают возможность генерировать зависящие от компиляции данные (в нашем случае mock-и);

  • если нужно, разработчик может использовать Bazel как для сборки, так и для запроса зависимостей через bazel query.

А вот тезис с поддельным GOROOT я не понял...

40 минут это был средний результат инкрементальной сборки на 7-ми машинках в параллель. По нашим прикидкам, на одной машинке с холодным кэшем должно было быть часов 15.
В основном это время уходило на линковку тестовых бинарей: каждый пакет с тестами собирается в отдельный исполняемый файл и на это уходит чудовищное количество времени и дискового пространства.
На втором месте собственно исполнение тестов.

Об этом я писал здесь: https://habr.com/ru/company/joom/blog/718340/
Основная цель: сокращение времени сборки в несколько раз (до миграции среднее время на сборку было порядка 40 минут, после 12 минут).
При этом удалось оторвать кучу самопальных костылей и, в целом, сборка стала гораздо надёжнее.

Гранулярность Bazel-а при сборке Go-проектов - пакет.

То есть, если в пакете поменялся один файл, то пересобрать придётся весь пакет и, скорее всего, всё от чего он зависит.

Здесь, как мне кажется, Bazel может дать ускорение только за счет следующих моментов:

  • не нужно будет каждый раз пересобирать зависимости данного пакета;

  • если пакет не менялся, то его тесты могут быть закэшированны;

  • можно распилить тесты на https://bazel.build/reference/be/common-definitions#test.shard_count (грубо говоря, будет параллельно вызываться один и тот же исполняемый файл с разными аргументами, каждый раз выполняя часть тестов пакета);

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

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

В результате, к примеру, зачастую для проверки компилируемости проще и быстрее закинуть ветку на CI.

В нашем случае просто проверка "а код вообще компилируется?" занимала более получаса.
Мы уже успели навернуть распараллеливание тестов, инкрементальный запуск тестов в зависимости от изменённых тестов, распил самих тестов и время запуска на CI всё еще было очень печальным.

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

На сколько я понимаю, Bazel имеет следующие пенальти:

  • время анализа;

  • создание песочницы на каждый шаг;

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

Особый плюс Bazel-я проявляется при использовании общего кэша и фермы для сборки.

С кросс-компиляцией действительно всё плохо, но если не используется CGO, то тут спасает кросс-компиляция в самом Go.

Ну и интересно, когда именно Вы стокнулись с этими проблемами и какую ферму/общий кэш использовали?

Я изначально то же ждал от go.work совершенно другого поведения: он меня интересовал в контексте работы с несколькими go.mod в рамках монорепозитория.

Но он сделан для другого:

  • решение проблемы с IDE, которые используют gopls для интеграции, например VS Code (в этом случае при работе с несколькими go.mod надо открывать по одному экземпляру IDE на каждый go.mod);

  • решение проблемы работы с несколькими связанным go.mod в разных репозиториях.

Если для Вас эти сценарии не актуальны, то эта фича действительно выглядит предельно странно.

В go.work явно перечисляются используемые go.mod-ы.
Если директория с go.mod там не указана, то GoLang будет её игнорировать и запустить из неё без ключа -workfile=off не получится. Будет ошибка вида:

go: no modules were found in the current workspace; see 'go help work'

1
23 ...

Информация

В рейтинге
Не участвует
Откуда
Москва, Москва и Московская обл., Россия
Работает в
Дата рождения
Зарегистрирован
Активность