-
Проблема XY (2)
Продолжение недавнего поста о проблеме XY. На этот раз — с конкретным примером.
В сообществе Кложи кто-то спрашивает: подскажите профайлер, чтобы отладить код. Выкидывает OufOfMemoryException (OOM), потому что утекает память.
Ему накидали вариантов, я тоже добавил свой. Но меня не покидала мысль, что никакого профайлера не нужно. OOM — довольно специфичная ошибка, и случается она по двум причинам: либо ты пишешь что-то незаурядное вроде интерпретатора, либо полный говнокод.
Слово за слово, и человека уговорили показать упрощенную версию кода, в котором течет память. А там… как бы вам описать? Идея очень простая: нужно пройтись по строкам файла, сжатого GZIP-ом. В каждой строке лежит джейсончик. Его нужно минимально обработать и записать в базу, а сломанные записи собрать для будущей починки.
Каждый писал такой код сто раз: это банальный цикл с try/catch. Что же было у автора? Ощущение, что он собрал все выкрутасы, какие только знал. Своя ленивая коллекция через lazy-seq, замкнутая на открытом Reader-e. Глобальный атом, накопление ошибок в иммутальный вектор вместо логов. Функция, которая возвращает функцию. И это только сокращенная версия! Настоящая химера: тело льва, крылья орла, хвост змеи. И где-то здесь течет память. Счастливой отладки!
Я написал ему, что код переусложнен и нужен не профайлер, а рефакторинг. Выслал черновик с простой версией кода. А у него включились обижульки: я не просил критиковтаь мой код, это плод моих трудов, я задал конкретный вопрос, ты токсичный. Я ответил, пусть токсичный, но проблемы это не решает: код переусложнен, профайлер не нужен, а нужно радикальное упрощение. Чем закончилось, не знаю. Судя по последнему сообщению, он ждал установки профайлера на сервере.
Во вступительной части я описывал пример: кто-то не может поставить программу из-за ошибки. Той программой является очиститель реестра, подсказанный в курилке. Почистишь — и комп перестанет тормозить. Глупо, но такие истории случаются, и они простительны офисному работнику.
Чем это отличается от примера с профайлером? На мой взгляд, ничем. Это чистый, незамутненный пример проблемы XY. Автор написал говнокод и надеется, что профайлер каким-то образом его исправит. Нет, не исправит, а только займет лишние пару дней на установку и чтение документации. И пусть даже найдется место, где память течет — как это повлияет на код в целом? Говнокод останется говнокодом.
Вроде бы автор не офисный работник или таксист, а программист, но не понимает этого.
-
PostgreSQL в браузере
Пишут, что появился Постгрес для браузера, скомпилированный из сишных исходников в WASM. Размер 3 (три) мегабайта. Работают встроенные расширения, включая триграммы, ts-вектор и прочее. Открыл REPL на сайте и поигрался с командами – работает! Это настолько хорошо, что напоминает сон из детства.
-
Старье (1)
С вами новая рубрика “Старье”. В ней выходит все то, что можно назвать старьем. Зачем? Потому что новый контент вам и так закинут, а кто же подкинет старый?
В первом выпуске: короткометражный фильм “Математик и черт”. 20 минут, СССР, 1972 год:
На что обратить внимание: манера съемок и монтажа, спецэффекты. Детали быта, курение в комнате, слегка пренебрежительное отношение к женщине.
Ну и главное: СССР не жалел денег на популяризацию науки.
В комментариях отметился один из тех, кто участвовал в съемках фильма. Судя по датам — глубокий дедушка.
-
Феминитивы
Признаться, меня смешат феминитивы: редакторка, дизайнерка, врачка и так далее. Когда слышу их, либо улыбаюсь, либо прикусываю щеку, чтобы не рассмеяться.
Однажды я был в сообществе, где так общались всерьез: дизайнерка Маша закончила макет, ждем фотографку Глашу.
Подход с суффиксом “ка” мне кажется крайне унылым. Блин, ну нельзя механически добавлять его к слову, чтобы получился феминитив. Редакторки и врачки — настоящее издевательство над языком; произносящим такое должно быть стыдно. Я из принципа не доверю работу редакторке, фотографке, режиссерке и так далее. Подучите сперва русский язык, что ли.
Как же быть, если все-таки хочется феминитива? Ответ — проявить фантазию. Люда Сарычева подписывается “редакторицей” — разумеется, в Телеграме и только в шутку; на обложке она — редактор.
Суффикс “ка” хорошо заменяется суффиксом “ша”. Парикмахерша, кассирша, дизайнерша, операторша, редакторша. И звучит привычней, и с толикой юмора. Я старшая дизайнерша отдела!
С фотографкой еще не придумал, но русский язык на то и могучий, чтобы справиться с этим.
PS: программисткам и разработчицам не о чем волноваться, все у них хорошо.
-
Расставание с сервисом
Предположим, вы решили расстаться с каким-то сервисом. Кнопки “удалить аккаунт” в приложении нет, поэтому пишем в поддержку: добрый день, прошу удалить учетку.
Сотрудник поддержки, получив такое сообщение, спросит “а почему” или “что не устроило”. В результате процесс повиснет, пока не ответишь – а там еще две-три итерации уговоров. К концу процедуры хочется разбить сотруднику лицо.
Разумеется, это эмоции. Умом я понимаю, что у сотрудника нет права думать, и он действиет по скриптам. А скрипт такой, что клиента нужно уговорить от ухода: предложить скидку или грейс-период. Возможно, клиент принял решение спонтанно. Может, он пьяный или прочитал какую-то дичь в интернете.
Но лишь одной деталью можно перевернуть процесс с ног на голову. Нужно показать клиенту, что сообщение принято и взято в работу, а выяснения почему и отчего теперь протекают в фоне, не блокируя процесс. Другими словами, если над скриптами работал нормальный человек, ответ был бы таким:
Ваше сообщение принято, начинаю процесс удаления. Это займет время. Пока выполняются все шаги, скажите, чем вызвано ваше решение?
В результате я вижу, что процесс не повис на встречном “почему”, и могу поговорить.
Разумеется, процедуру удаления начинать не нужно — подождет. Главное, что клиент понял: его услышали и не собираются устривать торги как на базаре. Пусть даже это иллюзия.
PS: Уже после публикации вспомнил, как закрывал подписку у Адоба. Жму на кнопку отмены и получаю: какая жалость, отписка не сработала, переключаю на оператора. Открывается чат, на линии Сулим Кумар. Начинается восточный базар: а почему, а отчего, давай скидку 5, 10, 15 процентов. В лучших традициях “Поля чудес”. Спустя двадцать минут он сдался, но ощущение осталось именно как от боя. Почему Адоб не понимает, что железная хватка только усугубляет желание расстаться?
-
Проблема XY (1)
Поговорим о проблеме XY, и для начала — вольное определение. Проблемой XY называется случай, когда человек обращается за помощью, чтобы решить проблему X. Но решение нужно для того, чтобы решить другую проблему Y, о которой помогающий не знает. Это приводит к нелепым и даже печальным ситуациям.
Пример из жизни: человек пытается поставить программу, но при установке получает ошибку. Он пытается нагуглить решение — это проблема X. Но если спросить, что за программу он ставит, это окажется “Очиститель Реестра Премиум Плюс”, который сливает личные данные рекламным фирмам. Почистить реестр посоветовал коллега в курилке, когда бедняга пожаловался, что комп тормозит.
“Комп тормозит” и есть проблема Y — и она решается точно не очисткой реестра.
Вопрос в том, как относиться к проблеме XY с разных сторон. На StackOverflow и в чатах порой случается так, что на вопрос “как мне сделать X” отвечают “зачем тебе делать X?”. Слово за слово, и люди теряют лицо. Отчасти потому, что не всегда ясно, кто с той стороны: любитель погреть уши или специалист. Хотя на том же SO за человека косвенно говорит репутация.
Вопрос “зачем делать X”, хоть и бесит, помогает выйти из замкнутого круга. Случается, что проблема давит, ты в ступоре и напоминаешь зашоренную лошадь. В голове только одна мысль — как сделать X — и она не пускает другие мысли. Запросто может быть так, что делать X на самом деле не нужно. Вопрос о значимости X может вернуть мозги в русло, пока еще не поздно.
Раньше я считал, что на вопрос об X надо отвечать буквально. Что выходить на уровень выше, когда у человека горит, некрасиво. Позже я придумал более тонкую схему, когда сначала даешь буквальный ответ, а затем, когда собеседник успокоился, плавно вытягиваешь из него весь бекграунд. Это хорошая схема, и она работает.
Возможен более грубый подход: если видишь, что человек занимается ерундой, сразу сказать ему об этом. Плохо работает с обижульками, можно прослыть “токсичным” — обожаю это слово. Зато экономит время и делает общение линейным, а это много значит. Если человек выслушал критику и не включил обижульку — это замечательный человек. Такая экспресс-проверка на месте.
К проблеме XY я бы отнес другой случай, который называю дилеммой тренера. Знакомый тренер рассказывал про новичков, которые занимаются по урокам с Ютуба. Делают упражнения, к которым нужно переходить спустя месяц занятий. Берутся за неадекватные веса или положения, от которых только боль и никакой пользы.
И без тренера я видел подобных ютуберов. Даже на мой любительский взгляд они занимаются либо в лучшем случае без пользы, либо с опасностью для тела. Дилемма тренера в том, что либо он подходит говорит, как правильно, либо игнорирует. Опция “подойти” чревата тем, что иным посетителям не нравятся непрошенные советы — вплоть до того, что они уходят в другой зал. Выходит, тренеру нужно тщательно обдумать и подобрать слова, а не всегда есть на это силы. Можно игнорировать, но в таком случае как бы попускаешься принципами, которым служишь.
Словом, у проблемы XY нет внятного решения, все зависит от ситуации. И хотя вывод в высшей степени капитанский, признайте, что проблема XY вокруг нас каждый день, и нужно как-то ее разруливать.
Эту тягомоту я написал затем, чтобы плавно подойти к одному случаю, но о нем — в следующей заметке.
-
Не было времени
Иногда что-то сделано плохо, и с той стороны говорят: у меня не было времени. Например, нет детальных логов, сервис валится без понятных сообщений, что-то не заводится.
Понимаешь, мы торопились, не было времени.
Это полная ерунда. Истинная причина в том, что человеку не хватило опыта, чтобы сделать хорошо сразу. Например, перехватить исключение и вывести понятное сообщение. Или чаще писать логи. Или слать репорты, если что-то не работает.
Тыкать в лицо этим не нужно. Хочется верить, что человек, которому “не хватило времени”, подучится и в следующий раз сделает как надо. Можно провести внутренний вебинар или написать док, который описывает, как надо. Внутри, не называя имен, объяснить, что было сделано плохо, кому было больно и почему, и как нужно было.
Ну а если не помогает и человеку по-прежнему “не хватает времени” — это тревожный знак.
-
Современный фронтенд
280 запросов и 50 магабайтов – вот что нужно фронтендеру, чтобы отрендерить одну страничку. Уж простите за неровные склейки, но скриншот верный: в нем действительно 280 запросов плюс-минус один.
Спрашивается, как же не испытывать ненависти к фронтендерам? Вы же расходуете трафик и сжигаете проц. А потом обижаетесь, что в ваш адрес пишут обидные слова. Как же не писать?
Да, бекенд тоже бывает не сахар, но на то он и бекенд, что берет трудности на себя. А здесь трудности перенесли на мою машину, на мои ресурсы. Кто об этом просил?
На этом месте часто говрят: а что ты предлагаешь? Опять свой HTMX и серверный рендер? Нет, я предлагаю хотя бы подтереть сопли, например:
- почему одна и та же ревизия файла скачивается много раз?
- почему стили не собраны в один?
- то же самое со скриптами: почему они не собраны в один?
- почему скачиваются десятки гифок? Спрайты, не слышали?
Деградация фронтенда просто ужасает, и ни малейшего просвета не видно. Наоборот, все больше обезьянок с реактом и клиентским рендером.
-
Баг в AWS
Расскажу, какой баг отлаживал недавно. Как обычно, он оказался вложенным, когда один баг основывается на другом, тот — на третьем и так далее.
Ситуация: один сервис генерит CSV-файл и складывает в S3. После чего вызывает почтовый сервис со словами “отправь этот файл по почте тому чуваку”. Все это работало до тех пор, пока народ не пожаловался, что файлы не приходят на почту.
Смотрю логи, файл сгенерился и лежит в S3. Почтовый сервис при попытке скачать его кидает исключение “stream is closed”. Оказалось, особо умный разработчик намудрил с классами. Ему нужен был не только
InputStream
, но и поле из заголовков. Вместо того, чтобы вернуть пару(stream, field)
или мапу с ключамиstream
иfield
, он строит анонимный экземплярInputStream
, который проксирует исходный стрим и несет дополнительное поле.Разумеется, он не протестировал все как следует, и при особых условиях стрим был nil, а JVM считает, что нулевой стрим означает его закрытие. Отсюда “stream is closed”, хотя причина в другом.
Эта шелуха отняла порядочно времени. Но я все-таки выяснил, что исключение было от того, что файла в S3 нет.
Лезу в бакет — файл есть.
Смотрю логи еще раз. Выясняется, что файл появился через секунду после того, как почтовый сервис обратился к нему. Это бред, потому что файл записан в S3 еще до вызова почтового сервиса!
Смотрю внимательней и замечаю: я записываю файл csv, а почтовый сервис ищет такой же, но с расширением .xlsx. И до сих пор это срабатывало: рядом с CSV автоматом появляется xlsx, и кто его генерит — не понятно.
После нескольких часов выяснилось следующее.
Люди, которые получали по почте CSV, пытались открыть его экселем, что кончалось слезами и болью. В точности то, что я описал в другой заметке. Они попросили выслать эксель, но разработчики сервиса слишком заняты, чтобы делать другим удобно. Нашелся девопс, который сделал следующее:
-
он повесил на бакет хук, который срабатывал при загрузке файла с расширением csv
-
этот хук вызывал лямбду с именем файла
-
лямбда была скриптом на Питоне, который переколбашивал CSV в эксель и записывал рядом
-
он поправил сервис отчетов так, что при вызове почтового сервиса расширение файла менялось с csv на xls.
Вот как это работало: сервис отчета сбрасывал файл csv в S3. Запускался хук с лямбдой, которая писала рядом xlsx. К тому времени как вызывался почтовый сервис, файл xlsx был уже в бакете, и отправка работала без ошибок.
А потом что-то случилось: то ли Амазон поправил тайминги, то ли слишком много сообщений в очереди, то ли Луна повернулась не тем боком, но — хук стал вызываться чуть позже, буквально на секунду или около. Этой секунды оказалось достаточно, чтобы почтовый сервис запустился раньше и упал.
Разумеется, нужно выкорчевать это осиное гнездо и сделать так, чтобы сервис отчетов писал готовый xlsx безо всяких хуков. Но у нас все срочно, сроки горят, поэтому просто подняли тайминги с обещанием сделать все как надо в следующий раз.
За это я и не люблю облачную инфраструктуру. Код в ней играет лишь малую роль. Много логики можно задать какими-то хуками, эвентами, очередями и прочими штучками. Они не прописаны в коде, они могут быть заданы вручную в дашборде AWS. Они могут быть в зарыты в YAML-файлах в devops-репозиториях. Человек, который воткнул этот костыль, может быть в отпуске, и кроме него о нем никто не знает.
Это подводка к следующему посту на тему айти. Кто-то думает, что разработчик учит Питон и пишет код, зарабатывая 300 тысяч в секунду. На деле разработчик занимается в том числе тем, что описано выше: два дня ищет баг в стоге сена размером со стадион, и правит его сменой цифры в конфиге.
Вы точно хотите в айти?
-
-
Обновление MacOS
Современная MacOS раздражает мелкими косяками. Из сегодняшнего: накатил минорное обновление, и пожалуйста: программа chromedriver опять считается опасной, недоверенной и прочее. Иди в настройки → безопасность → мотай до нужного пункта, жми “разрешить”, вводи админский пароль.
Все это я уже делал, но обновление сбросило флаги для сторонних программ.
Господа разработчики из Эпла, это же баг, его надо поправить. Почему вы гоните халтуру? Обновление не должно сбрасывать то, что я уже настроил.
Вообще, ощущение такое, что всех толковых разработчиков забрали в iOS, а десктоп пилят по остаточному принципу. Да и то — тупо копируют то, что на мобиле.