• Как я провел 2022 год

    Появилось время написать что-нибудь в блог. Ниже — коротко о том, чем занимался раньше и что делаю сейчас.

    После увольнения из Exoscale я устроился стартап Clashapp (ныне Huddles). Это мобильное приложение с короткими видео и встроенной валютой. Вместе с коллегами пилили бекенд на Кложе. В техническом плане проект был очень продвинут, многие вещи взял на заметку. Тимлидом у нас был Eric Dvorsak, и работать с ним было одно удовольствие.

    К сожалению, стратап не потянул финансовую часть. К концу года руководство сообщило, что “не будет возражать, если сотрудники найдут другую работу”. Первый раз в жизни услышал такую формулировку.

    Должен признать, что с поиском удаленной работы из России сейчас беда. Все требуют релокации, иностранные счета особо не помогают. К счастью, нашлись добрые люди, которые помогли устроиться в автралийский стартап.

    Работа в Австралии отличается графиком. Разница с офисом семь часов, пересекаюсь с руководителем буквально один час в день. Это первый случай в моей практике, когда разница столь велика. Есть и плюсы, и минусы. С одной стороны, приучает работать автономно, задавать вопросы, проверять задачи на точность. Полезно иметь пул задач, чтобы в случае затыка с одной переключиться на другую.

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

    Однако сломался привычный режим работы. Дело в том, что уже несколько лет я провожу дни одинаково: когда прихожу на работу, сперва трачу час на книгу, блог или библиотеки. Затем перекус и тупняк в интернет. Затем утренний созвон и работа на оставшийся день. Если я потратил час на себя, на остальное мне уже плевать: упал прод или нет, закрыли спринт или нет. Самое главное уже случилось, а остальное рутина. И когда этого часа не было, начинаю злиться.

    Так вот, из-за разницы во времени с Автралией каждое утро теперь начинается со звонка. Час на личные дела либо уходит во вторую половину дня, либо выпадает. Пытаюсь перестроить режим так, чтобы этого не было.

    Последние месяцы мало пишу в блог, потому что занимаюсь второй книгой. Много времени потратил на редактирование глав. Перед праздниками создал репозиторий, желающие могут посмотреть. Книга уже собирается в Докере, то есть прошла стадию глубокого черновика.

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

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

    Помогаю выпускнице, с которой делали диплом, найти работу Питон-джуниором. Ох непросто стало сейчас.

    В планах на 2023 год — выпустить книжку.

    Поздравляю всех с наступившим Новым годом. Желаю больше стойкости к стрессу и информационному шуму. Меньше пропускать через себя, чтобы не сойти с ума. Оставаться людьми. Это, пожалуй, самое важное.

  • Clojure Coding Guide

    TL;DR: this is a detailed description of how to write good Clojure code. It’s based on my 8 years of experience with Clojure for both commercial purposes and side projects as well. Some parts of this document repeat the well-known guide by Bojidar. Other parts instead break the conventional rules in Clojure development. For such cases, I give an explanation of why they are what they are. Everything written below has come from practice, and I hope you’ll find it useful.

    Table of Contents

    Parentheses

    Let’s start with something obvious yet worthy of repeating. When writing Lisp code, don’t balance parentheses as you did before in Python or JavaScript. Not like this:

    (time
     (doseq [a [1 2 3]]
       (let [b (* a a)]
         (println b)
         )
       )
     )
    

    But this:

    (time
     (doseq [a [1 2 3]]
       (let [b (* a a)]
         (println b))))
    

    The same rule applies to collections. The following code fragments look weird in Clojure:

    (def mapping {
       :name "Ivan"
       :email "test@test.com"
    })
    
    (def numbers [
      1,
      2,
      3
    ])
    

    It is a strong rule for every Lisp dialect and you’ve got to get on with it. The sooner you get an editor powered with a plugin to manage parenthesis the better it is for you as a programmer. Emacs + Paredit is a good choice but it’s a matter of preference.

    Read more →

  • Кто виноват

    Наверное, вы слышали: чтобы получить правильный ответ, задавайте правильный вопрос. И наоборот: неправильный вопрос займет массу времени и сил, но ответа не даст. Удивительно, что многие вопросы, что мы задаем, поставлены неверно. Один из них звучит как в заголовке — кто виноват?

    Стоит чуть-чуть подумать, как станет ясно, что это неправильный вопрос. Так ли важно, кто именно виноват? Что это дает? Как виновность поможет исправить ситуацию и предотвратить ошибку в будущем?

    Если взять историю любой катастрофы — Титаник, Чернобыль — везде окажется, что виноваты не люди на местах. Это очень желанно руководству, особенно если исполнитель умер. Непрофессиональные операторы взорвали реактор. Беспечная команда нашла на айсберг, и делу конец.

    Да что катастрофы, вспомним истории с падением прода. Всегда оказывается, что программист Вася запустил опасный скрипт с кредами от прода, которых у него быть не должно. Креды дал ему под честное слово админ во время попойки в баре. Креды выдаются по заявке, нужно собрать пять подписей, но гендиректору некогда, его зам на больничном и так далее.

    Когда сотрудник Гитлаба удалил базу с прода, выяснилось много вещей. Бекапы не работали, оповещения об ошибке бекапов тоже не работали. Пока петух не клюнул, никто не волновался.

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

    Представим теперь, что условного Васю взяли за шкирку и объявили: ты виноват. Кому от этого легче? Даже если Васю уволят, ситуация повторится в будущем.

    Верный признак, что вопрос вины неверно поставлен — он дает большой выхлоп. Вася виноват, но… и дальше экраны текста, что на самом деле чего-то там. Так быть не должно.

    Вместо “кто виноват” нужно спрашивать “кто несет ответственность”. Это все меняет: оказывается, вина и ответственность — разные вещи, которые делятся между людьми. Виноват один, отвечает другой. Как они разрулят между собой — не наше дело.

    Вася уронил прод и он виноват. Но отвечает техдиректор, потому что у Васи в принципе не должно быть доступа к проду.

    Оператор взорвал реактор и он виноват. Отвечают те, кто проектировал, вводил в эксплуатацию и тестировал.

    Капитан навел корабль на айсберг и он виноват. За нехватку шлюпок, за неумение команды спасти пассажиров отвечает перевозчик.

    Пьяный устроил дебош в клубе. Он виноват, но отвечает охрана, которая его пропустила.

    Сотрудник слил базу клиентов. Он виноват, но отвечает фирма — юрлицо. Будьте любезны штраф в десять тысяч за каждую строку. Сливы сразу прекратятся.

    Водитель в Воронеже сбил насмерть коляску с грудным ребенком. Оказалось, у него десятки неоплаченных штрафов за последние полгода. Он виноват. Но пусть начальник ГИБДД объяснит, почему водителю не аннулировали права.

    Правило: когда случилось что-то из ряда вон, ищите ответственного, а не виновного. Когда найден первый, второй появится автоматически. Но не наоборот: чаще имеем виновного Васю, с которого нечего взять, а ответственных нет.

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

    Сказанное имеет прямое отношение к сегодняшней ситуации. В России часто ищут виновных и находят их в лице американских президентов, англосаксов, оппозиции, инагентов и бог знает кого еще. Каждый раз, когда это слышу, в голове вопрос: ладно, пусть виноваты англосаксы, но кто несет ответственность? Если никто, что толку мне знать?

  • Интернет и геополитика

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

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

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

    Тезис о едином пространстве разваливается на глазах. Все меньше остается сервисов, куда можно попасть, не испытывая ограничений. Твиттер(1) и Инстаграм(2) заблокированы Россией. На Госуслуги и Налог.ру нельзя зайти, если ты не в России. Если уехал, ставь московский ВПН, что до недавнего времени звучало анекдотом.

    Порнхаб в одной стране разрешен, в другой запрещен, в третьей — только с авторизацией через местную соцсеть. Grammarly не работает с российскими IP, нужен ВПН. Украинские сайты показывают россиянам плашку с расчлененкой.

    Надоели сайты, защищенные Cloudflare. При каждом заходе видишь уродский экран с задержкой в 5-10 секунд. Иногда Cloudflare требует капчу с гидрантами и велосипедами. Двадцать минут — и сессия рвется, проверка начинается снова.

    Гугл и Ютуб боятся ВПН как огня. С ним Ютуб показывает капчу — не дай бог ты пройдешь мимо Большого Брата. Фейсбук, Твиттер и аналоги блокируют Тор. Им лучше знать, что безопасно, а что нет.

    Про Китай писать нет смысла.

    Сервисы все больше ведут себя как государства. Пользователь, чей IP вызывает малейшее подозрение, приравнивается к нелегалу, незаконно переходящему границу. Его надо схватить и подвергнуть деанону.

    Фейсбук и Твиттер открыто занимают позиции в социальных конфликтах США: выборы, BLM и так далее. Получить бан за поддержку Трампа теперь в порядке вещей. Не лучше ситуация и у нас, когда ВК и Мейл.ру сливают данные о тех, кто состоит в группах “оппозиции”.

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

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

    Очевидно, никакого свободного интернета нет, более того — не интернет двигает обществом, а двигают им. Современная дурь оседает в интернете и приводит к ограничениям по IP, странам, действиям режима и остальному.

    Получится ли сделать что-нибудь другое? Возможно, но это будет принципиально иной вид связи. Он должен быть максимально простым для пользователя и невозможным для блокировок. Примерно как блокчейн, хоть я и не люблю аналогии с криптой. К сожалению, лично мне этот новый вид связи трудно представить хотя бы приблизительно.

    1, 2 – считаются экстремистскими организациями или вроде того.

  • Мобильная деградация

    Последнее время я делю экран пополам: слева браузер, справа Емакс. Такой сетап нужен для определенной работы, связанной с редактированием текста.

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

    Но стоит уменьшить окно на пиксель, как вдруг:

    Кто-нибудь в курсе, зачем это? Код — самое главное на этой странице — пропал под выпадашку, хотя места достаточно. Появилась адская разреженность, кнопки сплющились, как будто по ним проехали катком. Кто вообще просил? Остается выругаться и расширить окно обратно.

    Досадно от того, что кто-то сидел над этой хитрожопой версткой, трекал часы в Джире, презентовал менеджерам. А пользователь мечтает развидеть и вернуть все взад.

  • Автодополнение

    В хромо-подобных браузерах есть полезная функция — сохранение форм. Дико выручает, когда в сотый раз вводишь имя, фамилию и почту на сайте. Буквально сегодня я заполнял форму на сайте налоговой шестнадцать(!) раз. Если бы не автокомплит, я бы, наверное, стер пальцы. Тем более умники-разработчики повы..бывались с некоторыми полями, и в них не работает вставка. Какой-то скрипт блокирует событие, я начал было смотреть в консоли, но в итоге плюнул на это.

    Удивляет, однако, то, что автокомплит нельзя редактировать. В очередной раз я вставил не то значение, и оно осталось в выпадашке навсегда. Теперь каждый раз, выбирая из нее пункт, надо быть осторожнее, чтобы не тыкнуть не туда.

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

    Между прочим, такая функция есть в Телеграме. Предположим, вы искали сообщество LaTeX, а нашли латекс и доминирование:

    Если тыкнуть в любой канал (ну, просто так), он останется в истории поиска. Будет неприятно, если это всплывет на созвоне при шаринге экрана. Крестик справа удаляет элемент из истории поиска, и с ним я спокоен: никакого доминирования мой собеседник не увидит.

    В общем смысле это ведет к правилу: собираешь данные — позволь клиенту их удалить. Удаление стоит усилий, порой огромных (привет GDPR), но тогда незачем и начинать.

  • Win-win

    Читаю книгу Егора “Наш код”. Хорошая книга, местами спорная, но ничего — просто держите в голове, что это Егор. Есть, однако, момент, мимо которого я не мог пройти молча — это эпизод с переговорами между двумя группами.

    Я хотел привести оригинальный текст, однако электронной версии, откуда можно скопировать и вставить, в интернете нет. Поэтому расскажу завязку своими словами.

    Есть группа разработчиков, которые пилят REST API, и есть группа потребителей. Понадобилась доработка сервиса, и потребители выдвигают условие: чтобы новые данные можно было забрать одним запросом. Разработчикам сервиса это неудобно: они сделали несколько новых методов, полагая, что потребители пошлют несколько запросов. Группы не сошлись во мнении, и начинается совещание.

    Read more →

  • Программа Preview

    Если я когда-нибудь пересяду с Мака на что-либо другое, больше всего мне будет не хватать… программы Preview. Да, встроенной программы просмотра изображений. Все потому, что Preview — невероятно мощный софт. Просмотр картинок и PDF лишь малая часть ее возможностей. Ниже я расскажу, что именно она умеет.

    (1) Банально, но все-таки — Preview открывает картинки и PDF. Не нужно ставить сторонний софт, который пропишет себя в автозагрузку и службы. С тяжелым сердцем вспоминаю Adobe Reader, который разросся до размера офисного пакета.

    Поставив Windows 10 на игровой комп, был удивлен, что в ней нечем открыть PDF (браузер Edge не в счет). По клику на PDF открывается магазин Microsoft – как это возможно в 2022 году, не понимаю. А на Маке сел — и читаешь PDF.

    Read more →

  • Коротко об lndir

    Небольшая заметка о утилите, которая требуется редко, но метко – lndir.

    Когда у меня стало больше одного Мака, появилась проблема синхронизации настроек. Другими словами, чтобы всякие .thisrc и .thatrc были одинаковы и подхватывались при изменении. Сюда входит конфиг Emacs, ssh, словари aspell, профили AWS, конфиги ctags, zshell и многое другое.

    Легче всего держать dot-файлы в репозитории и ставить симлинки. Неожиданно я столкнулся с тем, что не так легко написать shell-скрипт, который бы поставил симлинки на файлы из папки. Пытался при помощи find ... -execute и xargs, но постоянно что-то мешало. То отсутствие файла, то его существование, словом, всякие досадные случаи. В итоге было две команды: сначала одна удаляет симлинки, а вторая создает их заново.

    Оказалось, что lndir делает именно то, что я искал. Они принимает две папки и строит дерево симлинков из первой во вторую. При этом учитывает случаи, что я перечислил, например если симлинк уже есть. Благодаря этому дерево можно обновлять итеративно.

    Пример: в каталоге ~/work/System/Dotfiles хранятся оригинальные файлы Emacs, .ssh и прочие. Следующая команда make расставит симлинки в домашнюю папку:

    HOME = /Users/ivan
    PWD = $(shell pwd)
    
    create-symlinks:
    	lndir ${PWD}/Dotfiles ${HOME}
    	chmod 600 ${HOME}/.ssh/*
    

    Для файлов ssh необходимо выставить права 600, иначе утилита ругается.

    Синхронизация происходит обычным способом через git. Как только вы поменяли один из файлов, делаете коммит и пуш. На другой машине пулл и make create-symlinks, и все подхватывается. Репозиторий, понятно, должен быть приватным.

    По умолчанию lndir нет в поставке Линукса и Мака. Ставится из привычных apt и brew.

  • Интерфейс Гитхаба

    У меня бомбит от интерфейса Гитхаба. Он работает по странному принципу: показывает то, что не нужно и не показывает то, что нужно.

    Когда я открываю pull request, то хочу увидеть изменения в файлах. Поскольку я обычный программист, не гений и без заскоков, полагаю, это желание подходит большинству. Почти всегда, когда мне кидают PR, я знаю заранее, с какой задачей он связан, и сразу смотрю файлы. Только в редких случаях мне нужно прочесть описание.

    В интерфейсе PR файлы задвинуты на последнюю вкладку “Files changes”, и я не верю, что этому есть разумная причина. Файлы это суть PR, с какой стати задвигать их в конец? Это же самое нужное! Изменения должны быть сразу под описанием, чтобы не кликать, а просто смотать экран.

    Есть ли на этой вкладке хоть грамм полезной информации? Если да, чем он важнее 18 измененных файлов?

    Далее эти дурацкие табы. Проблема в том, что на вкладках располагаются не только данные, но и кнопки. Например, закрыть PR можно только со вкладки “Conversation”. А поставить аппрув только со вкладки “Files”. В итоге постоянно кликаешь на первый и последний табы.

    Первый и последний, Карл! Уже это говорит, что как минимум они должны быть рядом, если не объединены в один.

    По этой причине я пользуюсь трюком: когда кидаю ссылку на PR, добавляю к концу /files, то есть не ...project/pull/3, а ...project/pull/3/files. При таком раскладе у человека сразу откроются файлы, и не придется переключать табы. Мелочь, а приятно, особенно если собеседник понимает этикет и отвечает тем же.

    Судите сами: вот мне пришел PR с комментарием. Рассмотрим действия, которые я должен выполнить для мерджа:

    • открыть ссылку на PR;
    • перейти на files, чтобы бегло посмотреть, что внутри;
    • если все хорошо, вернуться на вкладку conversation;
    • нажать merge;
    • нажать delete branch.

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

    Из-за особенностей интерфейса кнопка “delete branch” находится выше “merge”, то есть сначала нажимаешь ту кнопку, что ниже, а потом выше. Это ни в какие ворота: экран мотают сверху вниз, и чем ниже кнопка, тем она важнее.

    В целом интерфейс Гитхаба шумный и грязный. На закладке “Conversation” схематично указаны коммиты, хотя есть отдельная вкладка “Commits”. Зачем размазывать их по двум вкладкам? Все, что касается коммитов, должно быть в “Commits”.

    Даже если у PR нет описания, будет пустой комментарий вида:

    igrishaev commented 20 minutes ago
    No description provided
    

    Спрашивается, что именно commented? Зачем писать о том, чего нет?

    Особую грусть вызывает мобильное приложение Гитхаба. Почему-то оно не может нормально показать код: кнопка “Browse code” вечно болтается внизу. Что мешает сделать ее первой? В этом плане Гитхаб напоминает современный Дропбокс: приложение плохо показывает то, с чем работает.

    Однажды я хотел закрыть PR со спамом, но не нашел кнопку “Close pull request”. Возможно, она была под выпадашкой или вроде того, но увы, я пас.

    Слева: где посмотреть код? Справа: как закрыть PR?

    Мне кажется, интерфейс Гитхаба разжирел, и пора устроить ему чистку. Он достиг стадии “впихнуть невпихуемое”, как это бывает с продуктами, которые часто выкатывают фичи. Интерфейс должен щадить пользователя: не вываливать на голову все подряд в надежде, что кому-то пригодится. Интерфейс — это оборона пользователя от того ада, что творится на серверах. Давайте помнить об этом, хоть я и не верю, что дизайнеры Гитхаба меня услышат.

Страница 28 из 86