-
Правда
Есть фееричное по своей глупости выражение: на правду не обижаются. Это верно: обижаются не на правду, а на бестактность, грубость, фамильярность, непрошенное мнение и все то, что сопутствует правде.
Если собеседник обижается на правду, стоит подумать, как лучше ее донести и вообще — стоит ли ее доносить.
-
Дело раскрыто
Однажды я писал о том, что Слак отказался работать с интересной формулировкой: устарела операционная система. Я обновил приложение, но не помогло. Очевидно, Слак захотел доступ к какой-то функции, которой нет в текущей операционке. Я решил, что эта функция нужна маркетингу или “более удобным” обновлениям.
Так и вышло!
На ноуте, которым я пользуюсь реже всего, я обновился по самые помидоры, чтобы знать, к чему готовиться. Накатил операционку, Слак и прочий хлам. И вот что происходит: когда Слак находит обновление, он хочет поставить его автоматом. Но не хватает прав, и выскакивает такая модалка:
Приложи пальчик, а дальше я сама.
Эта модалка действует на всю систему. Она вылазит не в Слаке, а на уровне операционки. Если бы пишете код, шарите экран, смотрите ютучик — будте готовы, что в любой момент она вылезет и потребует реакции.
На минуточку: она загораживает все! Вот такой прикол. Через час после закрытия Слак проделает то же самое, и модалка вылезет опять.
Разумеется, никаких настроек, чтобы это отключить, нет. С трудом нахожу слова в адрес людей, кто программировал эту дичь. Взята новая высота — или, скорее, пробито дно.
Но есть способ. Помните я писал про фаервол Lulu? С его помощью я отбираю у программ доступ в сеть, в том числе — к обновлениям. Оказалось, нужно добавить запрет как на картинке, и готово — доступа к обновлениям нет, модалка не появляется.
Все довольны, все смеются. Но блядским Слаком все равно стараюсь пользоваться реже.
-
Сервисы
Приходилось работать в проекте со множеством сервисов. Решил пожаловаться, какое же это неблагодарное дело — выскребать данные по углам, чтобы собрать конфету.
Ощущение, что сервисы делают люди, лишенные эмпатии. Например, есть метод
get-by-id
, чтобы взять сущность по айдишке. Угадайте, сколько сервисов поддерживаютget-by-idS
— получить список по айдишкам? В лучшем случае половина. У оставшейся половиныget-by-ids
возвращает сущности порциями по сто. Тебе нужно 250? Пиши обертку с пагинацией,next-page
,limit/offset
, вот это все.Вызывал сервис несколько тысяч раз? Начинаются разборки “кто нас дидосит”. Вызывай редко, не больше десяти раз, а еще лучше никогда. И везде проблемы с сообщением об ошибке. Передал что-то не то — иди смотри логи.
Я согласен с тем, что логику нужно разносить по сервисам. Но сервисы должны использовать общую шину данных: базу, очередь сообщений, файлы в S3 в конце концов. Гонять друг другу JSON выглядит хорошо в теории, но на практике — фу.
Условный Постгрес выплюнет миллион записей за доли секунды. Забрать этот же миллион из другого сервиса — приключение на неделю. Тут и метрики, лимиты, квоты, сетевые спайки, etc… А когда таких запросов несколько, сервис ложится спать.
Эти сервисы напоминают современного айтишника: хрупкого, тряпковатого мужчину 25 лет, который чуть что — выгорает. У которого все токсичны и вообще — отстаньте.
Удивляет, что подобные архитектуры строятся намеренно, и их создателям платят большие деньги. При этом опция “легкий доступ к данным” в архитектуру не входит.
А мне разгребать.
-
Карго-культ (2)
В комментариях к прошлой заметке один из читателей заметил, что эксперимент с обезьянами — выдумка и никогда не проводился. Похоже, он прав!
Впервые эксперимент упоминется в книге Competing for the Future by Gary Hamel and C. K. Prahalad. Вот дословная цитата:
4 monkeys in a room. In the center of the room is a tall pole with a bunch of bananas suspended from the top. One of the four monkeys scampers up the pole and grabs the bananas. Just as he does, he is hit with a torrent of cold water from an overhead shower. He runs like hell back down the pole without the bananas. Eventually, the other three try it with the same outcome. Finally, they just sit and don’t even try again. To hell with the damn bananas. But then, they remove one of the four monkeys and replace him with a new one. The new monkey enters the room, spots the bananas and decides to go for it. Just as he is about to scamper up the pole, the other three reach out and drag him back down. After a while, he gets the message. There is something wrong, bad or evil that happens if you go after those bananas. So, they kept replacing an existing monkey with a new one and each time, none of the new monkeys ever made it to the top. They each got the same message. Don’t climb that pole. None of them knew exactly why they shouldn’t climb the pole, they just knew not to. They all respected the well established precedent. EVEN AFTER THE SHOWER WAS REMOVED!
Эксперимент зашел публике, и его стали широко использовать. Позже несколько людей пытались узнать подробности: кто и когда проводил этот эксперимент. Но один из авторов умер, а второй отвечал отписками через секретаря. Самое интересное, что удалось из него выжать:
Our apologies, but Professor Hamel does not have the original source information at hand in terms of your request.
Похоже, эксперимент был выдуман авторами, чтобы придать вес другой идее. Возможно, они слышали что-то краем уха от зоологов, а остальное додумали. Надо иметь в виду, что книга написана в 1996 году, когда интернет был убогим, и проверить информацию было невозможно.
Напоминает историю про 25 кадр, который, в отличие от обезьян, был полностью развенчан.
Я получил урок, что все популярные истории нужно проверять. Не так уж и трудно было погуглить несколько минут. Александру, который написал об этом, больше спасибо.
См. обсуждение на Stack Exchange.
-
Карго-культ (1)
Возможно, не все знают, как работает карго-культ у обезьян. А это очень интересно.
В вольер с обезьянами вешают приманку: всякие сласти и ништяки. Если к ней притронуться, обезьян обливают холодной водой. Из-за своей физиологии им это очень неприятно, гораздо неприятней, чем людям.
Обезьяны быстро понимают, что приманку трогать нельзя. Когда в вольер подсаживают новую обезьяну, старожилы запрещают ей приближаться к приманке.
Дальше самое интересное: постепенно из вольера убирают обезьян, которых обливали. Остаются те, которым только запрещали трогать приманку, но которые не знают последствий. И все равно: они рьяно запрещают подходить к приманке новичкам.
Мораль — команда не должна быть обезьянами в вольере. Все запреты нужно время от времени пересматривать, чтобы не растить карго-культ. Удивляет, как часто я слышу объяснение в духе “мы делаем так, потому что мы так делаем”. Пусть не все, но некоторое из этого нужно сесть и пересмотреть.
Сказанное не значит, что нужно быть бунтарем и расшатывать основы. Здоровый баланс между крайностями — вот что нужно соблюдать.
-
Лук
Что ж, таки подъехал новый лук от Гугла. И не соврали: современный и прочувственный, что бы это ни значило.
Главное, теперь мы знаем: форму даже с одним импутом можно растянуть на 80 процентов площади. Дизайнерам воздушных интерфейсов взять на заметку.
-
Firefox и обновления
У меня сложные отношения с Firefox. Все как в песне: мое тело говорит да, но мое сердце говорит нет. Иногда я пытаюсь начать с чистого листа, но Firefox делает все, чтобы этого не случилось.
Когда вышел Хром, он поразил меня отладочной консолью. Сегодня это норма, но тогда, десять лет назад, нигде не было такого легкого доступа к сетевым запросам, логам и реплу Javascript. В FF было что-то на голову ниже, но в виде плагина, а тут — из коробки. Пока писал, вспомнил — Firebug, вот как он назывался.
Когда FF догнал Хром плане консоли, я пользовался им какое-то время. Потом устроился в фирму, где были токены Yubikey. В Хроме они работали из коробки, а что в FF? Надо скачать и поставить OpenSCP, затем добавить девайс в FF и прописать путь к бинарнику. Сам он не может. В итоге худо-бедно работало, но с перебоями и перезапуском браузера. Вернулся в Хром.
Сегодня я работаю в фирме, где тоже выдают Yubikey. Я открыл FF, и он сходу кидает модалку, которая просит пароль к токену. Минуточку, кто тебя просил? Нет ни одной вкладки, которая просит авторизации. Зачем кидаешь модалку? Тем более что токен нужен bash-скрипту для VPN, а в браузере он не используется. Какой-то бред.
Ладно, стерпим и это. Но с какой-то версии FF запретил опцию “не ставить обновления”. Либо они ставятся автоматом, либо браузер долбит мозг постоянной плашкой “вышел апдейт, поставь немедленно”. А у меня пунктик — если программа кричит об обновлениях, я либо отключаю их, либо не пользуюсь программой. И отключить никак не выходит.
Я пошел в
about://config
и прошелся по всем атрибутам, содержащим “update” в названии. Таковых нашлось штук двадцать. Менял так и этак, ставил 0, -1 и false — ничего не помогает. Проклятая плашка регулярно вылазит.Похоже, опять не судьба выстроить отношения с FF, но я все-таки спрошу. Как в FF ставить обновления по требованию? Чтобы я нажал “install update” и оно обновилось, а до этого молчало? Неужели Firefox, наше все, звезда опенсорса и все такое, больше на это не способен?
Верю, что способен. Вам слово.
-
Firefox и полиси
На выходных посидел с Firefox. Понял, как заблокировать обновления, а также много чего другого.
Если коротко: демократия закончилась. Начиная с какой-то версии Firefox перешел на систему полиси для расширенных настроек. Редактор about:config по-прежнему работает, но нужно понимать: многие опции теперь — бутафория. Можете до посинения что-то включать и выключать, эффекта не будет.
Теперь Firefox работает с полиси. Это JSON-файл с директивами, которые включают ту или иную функцию. По сравнению с about:config преимущество в коллекциях: в полиси можно задать массив объектов, например, для настройки расширений или mime-типов, а в
about:config
все было плоским.Полиси описаны в формате JSON, но на Маке используется яблочный формат plist. Может быть, JSON тоже можно, но я не проверял.
Преимущество полиси в том, что можно задать поведение браузера до последних мелочей. И все это — в текстовом файле, который хранится в Github. Не нужна облачная учетка для синхронизации — вы сами решаете, как раскидывать файл по машинам. Я положил в приватный dotfiles, но приведу копию ниже.
Firefox не пытается оспорить то, что указано в полиси. Если сказано не ставить обновления — он не ставит. Сказано не проверять браузер по умолчанию — не проверяет. Никаких попапов, бейджей, нотификаций, алертов, всплывающих полосок и прочей ахинеи.
Теперь технические шаги. Все примеры будут под мак; на другие системы, думаю, переложить будет не трудно.
Firefox ищет полиси в разных местах, но самое очевидное — файл
~/Library/ Preferences/org.mozilla.firefox.plist
. ОпцияEnterprisePoliciesEnabled
означает, использовать ли полиси или пропускать их. Установите ее в истину командой:defaults write ~/Library/Preferences/org.mozilla.firefox EnterprisePoliciesEnabled -bool TRUE
Обратите внимание, что расширение
.plist
указывать не нужно.Чтобы выключить обновления, задайте
DisableAppUpdate
в истину:defaults write ~/Library/Preferences/org.mozilla.firefox DisableAppUpdate -bool true
Перезапустите браузер и откройте About Firefox или настройки — там будет следующее:
Обновления запрещены, никто не пройдет.
Список полиси можно посмотреть во вкладке
about:policies
. Выглядит так:Назревает два вопроса. Первый: как узнать, какие полиси есть в принципе и их значения? Второй: ты предлагаешь вводить их в консоли вручную?
Полный список полиси находится на этой странице, и он довольно велик. Проще скачать заголовку под вашу систему и поправить руками. Названия директив говорят сами за себя.
По второму пункту — разумеется, нужно создать файл в редакторе, но в случае с plist есть нюанс. Файлы plist бывают двух форматов: текстовый и бинарный. В первом случае это XML с тегами
<plist>
,<dict>
и<key>
. Во втором случае там байты вперемешку с текстом.Беда в том, что Firefox работает только с бинарным plist: если положить текстовый, он его игнорирует. Бинарник можно поправить в XCode, но это неудобно: не станете же вы хранить бинарь в Github и редактировать программой, которой нужно 15 гигов. К счастью, утилита plutil умеет импорт-экспорт, а заодно проверяет формат на корректность.
У меня получилась папка в dotfiles со следующими файлами. Прежде всего это org.mozilla.firefox.plist, который я выложил в Gist. Вот неполный список того, что он делает:
- отключает обновления
- отключает проверку браузера по умолчанию
- отключает менеджер паролей, мастер-пароль
- отключает Pocket
- убирает партнерские ссылки, top-sites и прочий шлак на главной
- открывает PDF-файлы в Preview.app. Для меня это важно, потому что встроенные открывашки PDF, как правило, убогие
- отключает всякий трекинг и фингерпринт
- включает запросы нотификаций, локации
- блокирует попапы
- отключает “что новенького”, рекомендованные расширения, фичи.
Второй файл — конфиг Make, чтобы управлять конфигурацией. Он короткий, приведу полностью:
DOMAIN = ~/Library/Preferences/org.mozilla.firefox.plist SOURCE = org.mozilla.firefox.plist policy-import: policy-check defaults import ${DOMAIN} ${SOURCE} policy-false: defaults write ${DOMAIN} EnterprisePoliciesEnabled -bool FALSE policy-true: defaults write ${DOMAIN} EnterprisePoliciesEnabled -bool TRUE policy-check: plutil ${SOURCE}
Команда
policy-import
переносит настройки из текстового .plist-файла в бинарный в домашней папке. Она зависит отpolicy-check
, которая проверяет конфигурацию на корректность.Команды
policy-false
иpolicy-true
отключают и включают полиси. Дело в том, что пока они включены, вы не можете обновиться даже если захотите — функция запрещена. Чтобы это сделать, отключите полиси, перезапустите браузер, обновитесь, затем снова включите. На короткое время ужаснитесь тому, как жили раньше: браузер выплюнет сто попапов, что пора обновиться, сделать его главным по умолчанию, а вот здесь у нас новая менюшка, а вот новое расширение, ну и все такое.В общем, разобраться с полиси было полезно. По аналогии с Емаксом и прочими утилитами, я храню конфиг в дотфайлах и синхронизирую через Гитхаб. Опасение вызывает лишь то, что полиси все еще на этапе разработки. Не ровен час, обновишься — и все слетит.
Вроде бы хороший конец, но все равно — с толикой грусти. Эта борьба вызвана тем, что некие придурки спрятали опции из интерфейса. Не будь придурков — не было бы суеты, конфигов и прочего. Энтропия и трение — вот есть то, что здесь описано.
Напоследок — ссылки:
-
Файлы с мака на винду
Небольшая заметка, чтобы в будущем не искать в интернете.
Предположим, нужно перенести большой файл с мака на виндоуз. Сеть не настроена, файлы не пошарены, настроить все это займет час. В распоряжении есть флешка большой емкости, но вот засада:
-
файловая система NTFS на маке работает только для чтения;
-
яблочная файловая система APFS не видна в винде;
-
файловая система FAT32 работает в обоих средах, но не поддерживает файлы больше двух гигабайт.
Что же делать? Можно поставить продвинутый архиватор с поддержкой мульти-архивов. Это когда архив делится на тома foobar.zip.01, 02 и так далее заданной величины. Но ставить софт очень не хочется.
Оказывается, все утилиты есть в коробке. На маке делаем так:
split -b 2024m SomeMovie.mkv SomeMovie.mkv.
Последний аргумент с точкой — шаблон нарезанных кусков. К ним будут добавлены строки aa, ab, ac и так далее для правильной сортировки. Если исходный файл был 5 гигабайтов, получатся файлы
SomeMovie.mkv.aa
,SomeMovie.mkv.ab
иSomeMovie.mkv.ac
.Скидываем все добро на флешку, и теперь с FAT32 не будет проблем, потому что каждый кусок не превышает два гига. Чтобы собрать файл на винде, запускаем команду:
copy /b SomeMovie.mkv.* SomeMovie.mkv
Очевидно, это нужно делать не на флешке, а на жестком диске. Можно положить рядом батник, если собирать будете не вы.
Польза способа в том, что не нужен сторонний софт, права администратора и прочая ахинея. Просто работает.
UPD: в комментариях к написли про exFat, а я про него как-то забыл. Действительно, с ним все работает. Поэтому все, что описано выше, пригодится, если флешка мала. Например, когда нужно перетащить файл на 16 гигов, а флешка только два.
-
-
AWS, история третья. Разрывы
Все статьи из цикла AWS
- Амазон
- AWS, история первая. Внезапный мегабайт
- AWS, история вторая. Афина прекрасная
- AWS, история третья. Разрывы
- AWS, история четвертая. Когда null не совсем null
В третьей истории расскажу, как я страдал от сетевых проблем в Амазоне. Как абонент Уральский: раньше не было разрывов, а теперь есть разрывы.
У нас в проекте много лямбд, и каждая вызывает другие. При таком раскладе невыгодно передавать результат напрямую. Можно использовать S3 как шину данных. Например, одна лямбда вызывает другую и говорит: положи результат в такой-то бакет и файл. Затем опрашивает файл, пока он не появится.
Это удобно, когда результат огромен: иные лямбды производят CSV-шки по нескольку гигабайт. Не гонять же их напрямую между лямбдами. Но файлы привносят хаос: не всегда очевидно, кто произвел файл и кто его потребители. Если изменить путь, через день придет коллега из другого сервиса и скажет: мы каждый день забираем файл из этой папки, куда он делся? Или наоборот: ты обнаружил, что некий сервис производит удобный файл, в котором все есть. Через месяц он перестал появляться, потому что они переехали на что-то другое. Мы вам ничего не обещали.
Файлы CSV удобно стримить прямо из S3. Послал GET-запрос, получил InputStream. Передал его в парсер и готово: получается ленивая коллекция кортежей. Навесил на нее map/filter, все обработалось как нужно, красота. Не нужно сохранять файл на диск.
То же самое с форматом JSONL, где каждая строка — отдельный объект JSON. Из стрима получаешь Reader, из него ленивый line-seq, и пошел колбасить.
Неожиданно это схема перестала работать с большими файлами. Где-то на середине цикл обрывается с IOException. Чего я только не пробовал: оборачивал стрим в BufferedInputStream с разным размером, засекал время обработки, передавал опции в к S3… ничего не помогло. Запросы в Гугл тоже ничего внятного выдали.
У меня подозрение, что дело в неравномерном чтении. Когда вы читаете файл, Амазон определяет скорость забора байтиков. Поскольку мы читаем и обрабатываем стрим в одном потоке, чтение чередуется с простоем на обработку данных. В больших файлах я нашел записи, которые больше других во много раз. Возможно, что когда обработка доходила до них, ожидание было больше среднего, и Амазон закрывал соединение.
Я пытался повторить это на публичных файлах S3: читал в цикле N байтов и где-то на середине ставил длинный Thread/sleep. Но S3 покорно ждал аж две минуты, и эксперимент провалился.
Словом, я так и не выяснил, почему вылазит IOException, но смог это исправить в два шага.
Первый — файл S3 тупо записывается во временный файл, и дальше с ним работаешь локально. Перенос стрима делается одним методом
InputStream.transferTo
. Во время переноса ошибки связи не возникают.Второй — иные агрегаты достигают 3.5 гигабайтов, а у лямбды ограничение на 10 гигабайтов места. Скачал три агрегата — и привет, out of disk space. Поэтому при записи файл кодируется Gzip-ом, а при чтении — декодируется обратно.
Все вместе дало мне функцию, которая:
- посылает запрос к S3, получает стрим
- создает временный файл
- переносит стрим в файл, попутно сжимая Gzip-ом
- возвращает
GzipInputStream
из файла
Со стороны кажется, что вызвал
get-s3-reader
— и байтики потекли, делов-то. А внутри вот какие штучки.Примечательно, что в одном проекте я сам спровоцировал
IOException
. Разработчик до меня позаботился о переносе файла S3 во временный файл. Я подумал, что он просто не знает, как обработать данные из сети и убрал запись на диск. Возможно, он что-то знал, но не оставил комментария. А надо было!Из этой истории следует: никогда не обрабатывайте файл S3 сразу из сети. Сохраните его во временный файл и потом читайте локально — так надежней. Рано или поздно вы схватите
IOException
, а на расследование будет времени. Чтобы сэкономить диск, оберните файл в Gzip.
На этом я закончу истории про Амазон. У меня есть еще несколько, но они не такие интересные и сводятся к тезису “думал так, а оно эдак”. Ну и обсасывать одну и ту же тему уже не хочется.
Думаю, вы поняли, что в Амазоне хватает странностей. Это не баги, потому что все они описаны в документации. Примерно как в Javascript: никто не знает, почему
{} + [] = 0
, а[] + {} = [object Object]
. Да, в стандарте описано, но кому от этого легче? Выбирая Амазон, закладывайте время и деньги на подобные непонятки.