Pull to refresh
26
0
Александр Дербенёв @alexac

Senior Software Engineer

Send message

Стоит еще особо отметить, что использовать большинство хуков и тем более каким-нибудь скриптом сборки включать их для всех и каждого — плохая идея. Большинство хуков вызываются не только в тот момент, который ожидает автор хука, но и в еще и большом количестве неочевидных моментов. В гипотетической ситуации, когда кто-то добавляет в pre-commit хук вызов линтера, он практически гарантировано в какой-либо момент ломает кому-нибудь rebase. А если вместо линтера вызывается реформаттер, то это зачастую провоцирует гору конфликтов на каждый коммит затронутый ребэйзом. Ограничения на сообщение еще выглядят разумно, но что-то сложнее туда лучше не запихивать — слишком сложно отловить все моменты, когда это будет стрелять кому-нибудь в ногу.

Блин, этот мем такой баянистый, но почему-то его в последнее время так часто форсят, что аж тошно становится. Имхо, до этого мема в кдпв выглядело лучше.

Мне кажется, автор изначально описал модель, в которой не нужны черри-пики. Если есть feature-бранчи, то и работу надо вести в feature-бранчах, а не в мастере, и потом черри-пикать. Соответственно фиксы делать в релизных бранчах и подмердживать их в мастер, а оттуда уже в фича-бранчи. Получается классический git flow.


На предыдущем месте работы использовалась несколько другая модель, в которую черри-пики хорошо укладывались. Вся разработка шла в мастере, от которого отводились релизные бранчи. Релизные бранчи нельзя было вливать обратно в мастер — существовал апстрим-проект, из которого периодически подмердживалось очень много изменений как в мастер (из мастера апстрима), так и в релизные бранчи (из релизных веток апстрима). Мерджить релизные бранчи в мастер в такой ситуации не представлялось возможным — это провоцировало огромное количество проблем на пустом месте. Поэтому все фиксы делались в мастере, и если фикс нужен был также в релизной ветке, то он черри-пикался туда из мастера. В этой модели без черри-пиков было не обойтись. При этом они отлично решали проблему и не создавали конфликтов на пустом месте — ведь мастер и релизная ветки никогда не сливались. Иногда, правда, всплывали спецэффекты из-за того что черри-пики накладывались на релизную ветку не в том же порядке, в котором они накладывались на мастер, но это было достаточно редкой ситуацией.

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


С другой стороны, после gc можно было вызвать git repack, упаковать все в один или несколько пакетов и потом только вызывать git push, это могло уменьшить количество передаваемых данных и возможно позволило бы запушить без разделения на несколько посылок, хотя не факт и над тем, как разбивать коммиты на эти пакеты пришлось бы отдельно думать.

type(foo)

Возвращает тип объекта, ссылка на который записана в переменной. При этом у самой переменной типа нет — она может хранить ссылку на объект совершенно любого типа.


PEP484 ввел Type hints, которые указывают, что в конкретной переменной ожидаются объекты конкретного типа, но type hints не влияют на то, что происходит в рантайме. Интерпретатор практически полностью их игнорирует. И появились они в языке только в угоду тому, чтобы можно было сделать линтеры вроде mypy, которые их проверяют. Но при этом нет гарантий, что в переменную с type hint будет записан объект тип которого соответствует type hint.

Можно купить в штате, где налог на продажу равен нулю и привезти куда угодно, и возвращать ничего не придется. Только в условиях повсеместных карантинов сложно это сделать. Много есть вариантов. Я вот только сегодня заказал ноут из британского apple store, потому что курс фунта по отношению к евро сейчас упал, а пересылка из UK в Ирландию стоит копейки. ~€150 экономии на пустом месте.

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

1. Цены для штатов указаны в долларах и без налога, так как налог зависит от штата, в котором производится покупка. При оплате к ним добавляется налог, американцы к этому привыкли.
2. Цены для европы указаны в евро, с добавлением пошлины на ввоз и VAT.
3. Цены для россии указаны в рублях, с добавлением пошлины на ввоз и НДС.

Если брать цену в долларах, вручную конвертировать в евро, добавлять пошлины и налоги, то получаются цены из европейского магазина с очень маленькой погрешностью (в пределах 50-80€), что легко объясняется ошибками округления и неправильно выбранными курсами конвертации и декларированной стоимости для расчета пошлин и налогов.

Так что сама компания не берет больше в разных страннах за один и тот же товар. Она просто честно удерживает и уплачивает все пошлины и налоги, установленные в соответствующих странах.
Для iOS 12 все еще регулярно выходят обновления безопасности. Но да, мажорных обновлений больше нет.
Ну уж называть AF_UNIX костылем… Имхо, сейчас это очень недооцененная технология. По факту он:
1. Производительнее любого другого стека, так как ни при каких случаях не покидает пределов хоста.
2. Безопаснее, так как к нему невозможно получить доступ извне. Ни прослушать, ни взломать вас через него не смогут.
3. Имеет встроенное разграничение доступа на уровне fs. Мало иметь доступ к системе, чтобы получить доступ к сокету нужно еще и исполнять код от имени пользователя/группы, которым этот доступ разрешен.

Для любого взаимодействия внутри машины AF_UNIX будет предпочтительнее, чем AF_INET6/AF_INET. Это просто протоколы с разными целями.
Вот это, кстати, интересный кейс. Было бы интересно его тестировать. В текущем варианте мы этого не можем сделать, так как чтобы протестировать OTA, надо собрать еще одну новую версию и сделать патчи с текущей версии на новую. Я полагаю, этот кейс обязательно входит в финальное ручное тестирование апдейтов, которые уходят пользователям.
У нас в принципе нет механизмов даунгрейда версии. Нужен даунгрейд — бэкап данных/erase-install/восстановление бэкапа. Ну и все прекрасно понимают, что то что мы тестируем — позволяет поймать то, что билд совсем сломан, а не проверить то, что он хороший. Учитывая, что главные каналы обновления получают свежие сборки один раз в день, это просто ответ на вопрос, могут ли разработчики продолжать работать на сегодняшнем билде или лучше остаться на предыдущем.
Ну уж скажите, дичь. Давайте я расскажу вам, как это все живет у нас.

Для начала масштаб проблемы. У нас пяток классов устройств, у каждого — своя система. Одновременно для каждой системы ведется разработка над текущим релизом, следующим мажорным релизом и опционально следующим мажорным релизом + 1. Помимо этого есть минорные релизы, над котороыми работа может начаться одновременно с мажорным. Плюс специальные ветки для бета-версий, фиксов безопасности и отдельные ветки для фабрик, чтобы не показывать им весь софт до релиза. Это все дает примерно с десяток активных каналов разработки для каждого класса устройств. Примерно каждый год выходит несколько новых моделей почти во всех классах, поддержка старых осуществляется в течение нескольких лет. Это дает до нескольких десятков поддерживаемых моделей устройств на класс. У каждой системы есть несколько вариантов, для пользователей, для фабричного тестирования, для разработчиков, etc. Итого мы ежедневно получаем примерно 30-50 сборок систем в день и примерно 100 моделей устройств, на которых нужно проверить, что интересующие нас варианты систем хотя бы базово работают. Сейчас у нас больше 250 устройств, которые висят подключенными на почти трех десятках серверов и работают в CI. Осложняется дело необходимым на все это временем. Сборка всех изменений за сутки занимает примерно 6-8 часов, сборка всего — 13 часов. Еще 2-4 часа на то, чтобы смастерить образы системы для всех вариантов и для всех устройств. Отдельная история про построение OTA патчей и загрузку всего этого дела в архив, это идет в фоне и может занимать до суток. erase-install на одно устройство занимает примерно полчаса. Минимальный набор тестов еще минут 15.

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

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

Ну и да, мы единственная команда, которая проверяет все поддерживаемые устройства. Правда и набор тестов у нас скудный. Чтобы его пройти образ должен успешно установиться на устройство, не жрать 100% cpu, не крешиться в цикле, а процесс UI должен запуститься и не падать. Мы буквально отвечаем на вопрос «а пригоден ли билд к дальнейшему тестированию?», зато для всего.

У других команд есть всевозможные автотесты на функциональность, они работают на том же технологическом стеке, но на другом пулле устройств и они проверяют, как правило, одну модель для каждого SoC. Полностью же покрыть весь софт автотестами не реально — слишком быстро происходят изменения. В ручную тестируется просто большая часть системы.
Понятно, чем вдохновлялись дизайнеры этих роботов… images.app.goo.gl/acEdUL6817wtPx8H8
Весьма не абстрактного, а очень даже популярного и широкоиспользуемого. И этот фреймворк только-только хочет перестать поддерживать компиляцию без C++11. Так что вкоммитить такое в него будет сложно. Разве что под каким-нибудь фиче-флагом. Ну или будет жить в форке.
Прошу прощения, был не знаком с N3599. Если его использовать, то все действительно проще пареной репы.

К сожалению, несмотря на то, что это поддерживается в gcc и clang, насколько я понял, это предложение до сих пор не вошло в стандарт (все, что я смог найти, говорит о том, что это предложение сейчас в статусе Open и вообще не обсуждалось комитетом с 2015 года). Если переключить в вашем примере компилятор на последний доступный msvc, то он не скомпилирует этот код, причем с довольно забавным набором ошибок.

Мне очень нравится clang и я предпочитаю везде использовать именно его, но я не люблю писать compiler-specific код, не предусмотренный стандартом. По моему опыту это имеет свойство через некоторое время превращаться в очередные подводные грабли.

Если же использовать тот literal operator, который есть в стандарте, то нужно действительно повозиться с тем, чтобы вывести содержимое этого литерала в аргументы шаблона. Мне кажется, что это все-таки реально сделать в constexpr, но я в этом не уверен.
Я не стал писать эту часть, потому что сами по себе применения получаются очень интересными и стоят отдельного поста :). Ну и прежде чем о них рассказывать хочется сделать так, чтобы было что показывать.

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

Другой пример возник в ходе наколеночного проекта, который я пытаюсь делать для самообразования и просто в качестве развлечения. И я хочу сначала сделать из этого что-то относительно законченное, что продемонстрирует то, что приносит такой подход решения проблемы. Будет что-то готовое к показу — расскажу и покажу.
К сожалению, я подумал о возможности сделать вывод типа через кастомный литерал только когда заканчивал готовить этот текст и не успел проверить возможность реализации этого без макросов. При первом приближении подумалось, что:
1. Понадобится комбинировать такой литерал и decltype(), чтобы добиться того же эффекта.
2. Не очень тривиально вывести возвращаемый тип из строки.

Ну то есть будет выглядеть как-то вроде вот этого:
constexpr auto operator""_conststr(const char* data, const size_t size) {
  return ...;
}

using FooString = decltype("Foo"_conststr);


Я еще надеюсь проверить эту идею и возможно написать отдельное короткое дополнение к этому посту.
Разумеется. Но правильно проставленные типы вместе с внятными метками разделов позволяют проще и быстрее ориентироваться в том, какая система разделов на носителе и что где находится. Можно называть это правилом хорошего тона, перфекционизмом, занудством или чем угодно еще. Но когда я больше недели не трогаю флешку, на которой больше одного раздела, я предпочту глянуть на таблицу разделов и увидеть что где находится, хотя бы по типам.
fdisk $DEViCELINK <<EOF
n			# создать новый раздел
p			# печать раздела
1			# номер раздела


Поправьте комментарий, пожалуйста. p — это «primary partition», а не «печать раздела».
А еще в этом же скрипте было бы не плохо выставлять типы разделов (команда t у fdisk), те, что проставляются по умолчанию, не всегда соответствуют реальности.
Пробрасывать ssh-agent — настолько же не безопасно, насколько и кидать приватный ключ на удаленный сервер. root на сервере может как утянуть файлик с приватным ключом, так и утянуть сокет ssh-agent. И защиты от этого нет.

Information

Rating
Does not participate
Date of birth
Registered
Activity

Specialization

Software Developer
Senior
From 100,000 €