Читать в телеге. Когда-то там были посты не только от меня.
Бесполезные зависимости
Часто можно услышать разговоры, что вот раньше-то ПО было оптимизированным, а сейчас все жрет ресурсы как не в себя, особенно память. Но на это часто следует ответ, что сейчас больше абстракций, функции и т.п. и на самом деле это нормально.
Прошлогоднее исследование зависимостей java-проектов показало, что с 2011 по 2021 среднее число неиспользованных транзитивных зависимостей возросло с 20 до 60, и оно растет для большинства проектов. Т.е. бесполезный мусор на самом деле есть, и его размер растет.
Для чистки зависимостей рекомендуют использовать плагин DepClean, разработанный, разумеется, авторами статьи. Но, что иронично, с собственными зависимостями у этого плагина все не очень гладко, потому что там внутри две CVE :)
Не деплойте в облака пацаны, вы матерям еще нужны
Вообще на первый взгляд развернуть в облаке сервис звучит как неплохая идея — зачем тратить время на трахание с железом или с настройкой какой-то базы, когда можно “потыкать пару кнопочек” и все будет работать “само”. Тем более, что в облаке сейчас уже есть почти все: базы на любой вкус, куберы всякие, CDN, OAuth, метрики, аналитики, сертификаты, хранилища секретов и т.д., даже бэкенд целиком можно себе накликать (см. Firebase или AWS Amplify). Все это с интеграцией между собой и кучей плюшек из коробки.
Однако “all magic comes with a price”:
- Трахание с железом и сервисами на самом деле заменяется на трахание с настройками и нюансами облачного провайдера. Причем если опыт с сервисами и железом плюс-минус переносимый, то у каждого провайдера свои приколы, разумеется.
- Отдельно выделю вопросы распределения ролей, настроек доступов и прочих аспектов связанных с ИБ. Про свой опыт с гуглом уже рассказывал. Во всем это зрелый DevOps может на неделю сгинуть для простой задачи, а разраб — вообще умереть.
- Облачные версии сервисов часто представляются собой форк опенсорсных со своими “расширениями” (например, амазоновский OpenSearch — это форк ElasticSearch), обычно от старой версии. Иногда присутствует EEE во всей красе. Причем расширения обычно нужны для интеграции в облачную экосистему и хреново поддерживаются, а решение для опенсорсного варианта может не подойти для облачного.
- Поскольку сервисом управляете не вы, то может не получится его тонко настроить или поставить какие-нибудь плагины.
- Как следствие, возникает привязка к облачному провайдеру, когда съехать с облака становится очень дорого, потому что все настройки или даже архитектура заточены под него.
- Условия могут внезапно поменяться к худшему и это может быть затратно (например, недавно Heroku убрал бесплатный тариф)
- Конфиденциальность — гомоморфное шифрование пока не применяют, так что облачный провайдер имеет доступ ко всем данным.
- Если что-то сломается, то вы ничего не сможете с этим поделать, только ждать и надеяться, что все будет быстро исправлено.
- Ложная уверенность в 100% надежности облака могут привести к тому, что ночью никто не будет дежурить и следить за работоспособностью сервиса (впрочем, и без облаков это можно делать).
Получается, что если вы делаете что-то стандартное, то облака дают быстрый и (иногда) дешевый старт, а с ростом будете наталкиваться на ограничения. Тогда уже и стоимость будет выше, и слезть с облаков будет тяжело. Но для какого-нибудь пет-проекта или эксперимента это может и нормально. Может, я старомоден, но мне кажется, что купить/арендовать железку в дата-центре хоть и будет дороже в краткосрочной перспективе, но даст больше преимуществ и гибкости в долгосрочной. Крупняки так вообще свои облака строят.
Влияние размера организации на эффективность
Жизненная гипотеза: чем больше людей в компании, тем больше времени тратится на совещания и организацию работы, продвигаются те, у кого лучше подвешен язык, а те, кто собственно работу делают — уходят. В итоге ничего и не делается. Много усилий тратится на поддержание процессов, регламентов, отчетости и т.п., и в итоге результаты могут получаться по остаточному принципу. Формализация процессов, которая часто возникает при увеличении количества людей, хорошо работает для простых или однообразных задач, однако мешает при выполнении сложных задач. Сильная формализация затрудняет оценку достижений (а без формализации никак, потому что будут конфликты интересов), что может сильно демотивировать сотрудников, особенно если ценится только героизм устранения последствий, а не кропотливость их предотвращения.
В больших организациях часто более заметен принцип Питера: “В иерархической системе каждый индивидуум имеет тенденцию подняться до уровня своей некомпетентности”. При всем этом большие организации — это обычно стабильно: большая инерция для изменений (как положительных, так и отрицательных).
В (нормальных) маленьких компаниях меньше стоит проблема контроля и они лучше адаптируются к изменениям, но и риски там обычно выше. При этом менеджерам проще уделять внимание рядовым сотрудникам.
Интересно, что в некоторых компаниях решили проблему размера разделением на несколько мелких. Эдакие компании-микросервисы. Это забавно коррелирует с заявлениями в стиле “Наша компания большая, про нее много плохих отзывов, но все зависит от департамента/отдела/команды, вот у нас-то все классно!”
Имитация обрыва связи
Иногда требуется проверить, что приложение нормально восстанавливает свою работу после обрыва соединения. Можно, конечно, грохать сетевое подключение целиком, но влиять на работу других приложений — так себе идея, а если все еще и локально происходит, то грохать loopback интерфейс — совсем грустно.
Лучше убивать подключения более гранулярно. Для этого может пригодиться утилита tcpkill
— во время ее работы она будет обрывать подключения по фильтру. Например,
sudo tcpkill -i lo port 5672
будет убивать все подключения к локальному RabbitMQ. Можно оборвать только часть подключений с помощью подобной колбасы:
sudo netstat -natp | grep ':5672' | grep java | head -n10 | awk '{print $4}' | cut -d':' -f2 | xargs -L1 -P10 sudo tcpkill -i lo port
Тут с помощью netstat
выводятся все активные подключения, фильтруются по исходящему порту и приложению, обрезаются до исходящего порта и режутся по нему (я в шоке, что написал это без гугла).
alias при sudo
Оказывается, alias работает только для первого слова. Поэтому, если создать alias
alias ll='ls -lF'
то ll
будет работать, а вот sudo ll
— нет. Однако если текст alias заканчивается на пробел, то следующее за ним слово тоже будет проверено на alias.
Т.е. если добавить
alias sudo='sudo '
то sudo ll
будет работать.
Отличие команд и событий
Во всяких DDD и CQRS очень часто возникают команды и события. Объединяет их обычно то, что они обычно пересекают границы домена или контекстов, обрабатываются асинхронно и представляют собой (возможно устаревшие) ошметки информации о системе. На ранних стадиях проекта очень легко попасть в ловушку и реализовать их практически одинаково с технической точки зрения (а то и вовсе не разделять). Однако между ними на самом деле довольно много различий.
Семантическое. Команда и событие выражают разные сущности. Событие — это бизнес сущность, “что-то произошло”, обычно существительно + краткое причастие (например, “заказ создан”). Команда — это приказ, “надо что-то сделать”, и чаще это техническая сущность (например, “отправь e-mail”).
Количество потребителей и производителей. У команды “потребитель” ровно один — исполнитель команды, а у события — от 0 до бесконечности, причем они могу быть из разных доменов. Команду может дать кто угодно, а произвести событие о том, что “что-то случилось” — только одна сущность.
Срок жизни. Команду сделал и забыл (удалил), а событие обычно стоит сохранить для истории.
Порядок обработки. Обычно для команд не важен порядок обработки, потому что заранее команду создавать — это как-то тупо. А вот события лучше обрабатывать последовательно: вряд ли будет логично обработать сначала доставку заказа, а потом его создание (особенно если при этом клиенту шлется уведомление).
Как следствие, и технологии для потока команд и потока событий обычно стоит выбирать соответствующие: для команд лучше подойдут решения типа RabbitMQ, а для событий — Kafka.
Маштабирование старых приложений при HiDPI
Не все приложения, особенно старые, понимают, что включен режим высокого разрешения и надо поменять свой масштаб. Чтобы сделать это принудительно, можно сначала попробовать специальные переменные окружения, но они разные для каждого фреймворка и могут вообще не работать. В подобном случае мне помогла утилита run_scaled, которая создает временный логический экран с нужным масштабом специально для приложения.
Трейсинг
С удивлением обнаружил, что, оказывается, не все знают про существование трейсинга и зачем он нужен. В простейшем варианте он позволяет отследить все операции, которые совершаются в рамках одного логического запроса — например, как он пришел с фронта, какие микросервисы запрашивались, какие запросы к базе выполнялись и т.п. Для этого обычно достаточно создать уникальный идентификатор запроса (traceId), прокидывать его при всех взаимодействиях (например, через http-заголовки) и добавлять в логах.
При продвинутом использовании можно строить карту сервисов (кто кого вызывает), смотреть графическое представление выполнения запроса (сколько времени он “висел” в каждой конкретной операции или микросервисе). Причем это может быть полезно даже не в микросервисной архитектуре (если у вас есть хоть одна зависимость в виде базы или распределенной очереди).
Сравнительно недавно два конкурирующих стандарта, OpenTracing и OpenCensus, объединили в один — OpenTelemetry. Если у вас попсовый стек, то подключается обычно довольно легко с помощью инструментации на уровне какого-нибудь кубера или на уровне приложения (в JVM-мире это java agent). Визуализировать можно с помощью Jaeger. Если некуда девать деньги, то можно использовать монструозный Dynatrace или облачные решения, типа AWS X-Ray.
Нулевая терпимость к багам
В продолжение старого поста про то, что не надо игнорировать баги, даже если они мелкие. Часто слышал высказывание, мол, зачем тратить время на мелкие правки, на «перфекционизм», что ничего страшного не случится, особенно если баг особо не влияет не на что, что баг дешевле терпеть, чем править.
Однако при этом обычно редко рассматриваются такие факторы, как:
- снижение культуры разработки (например, зачем мне заводить баг, если все равно его не пофиксят, зачем мне стараться делать качественно, если на проде полно багов)
- снижение качества (например, мелкий баг может быть симптомом более крупной проблемы или маркером плохого процесса)
- снижение качества мониторинга (надо разделять известные и неизвестные баги в логах, для этого даже инструменты вроде Sentry делают; метрика количества 5xx может уже не показывать нормальную картину)
- некорректная работа прода (даже не из-за самого бага, а из-за сопутствующих проблем. Например, если плохо обрабатывать ошибки пользователя и кидать 500, то балансировщик может прихлопнуть работоспособный узел, при большой нагрузке такое чревато полной неработоспособностью)
- снижение культуры реагирования на алерты («да забей на этот алерт, он всегда орет из-за того бага»)
- увеличение когнитивной нагрузки (надо помнить известные баги, думать, править ли новые или нет и т.п)
Кому повысить зарплату?
Неплохой доклад про стратегии повышения зарплаты, в котором рассказаны базовые принципы и основные примеры, как не надо делать.
Очевидно, что надо повышать зарплату тем, кто больше приносит пользы бизнесу, а не кому больше надо, кто больше попросит или лучше себя продаст. При этом пользу надо как-то оценивать, но любую метрику, особенно количественную, мыслящий программист легко сломает и она перестанет отражать реальность.
Если оценивать что-то абстрактное, то надо трезво оценивать влияние конкретного сотрудника на это (например, продуктовые метрики могут расти сами по себе, а геройски решенная сложная задача могла быть решена и другим разрабом, просто ему назначили другую).
Одна из неплохих стратегий по мнению докладчика - определить текущее узкое место, и премировать по метрике, способствующей его устранению. Дополнительный совет: вместо измерения всех по какой-то общей шкале стоит опрашивать всех членов команды и сравнивать людей между собой (с правильно подобранными вопросами, разумеется). Кто набрал больше первых мест, тот обычно и молодец. Все-таки, относительные оценки людям даются лучше.