Под капотом RollerCoaster Tycoon: оптимизация как искусство сказать «нет»
RollerCoaster Tycoon (1999) до сих пор называют эталоном оптимизации. Крис Сойер написал игру почти целиком на ассемблере и заставил процессоры конца девяностых тащить парки с тысячами посетителей без единой просадки кадра — то, с чем многие современные градостроительные симуляторы справляются хуже на железе в сотни раз мощнее. Ларс Тофус в блоге Larst Of Us разобрал, как это устроено. Исходников игры нет, но есть почти эквивалент — OpenRCT2, побайтовая фанатская переразработка на годах реверс-инжиниринга. По ней и видно, насколько агрессивно вылизан каждый кусок.
Первое, что бросается в глаза, это типы данных под деньги. Сойер не брал один универсальный тип на все случаи, а подбирал размер под максимально ожидаемое значение. Общая стоимость парка может быть огромной, поэтому под неё отведено 4 байта. А цена товара в ларьке заведомо маленькая, под неё хватает одного байта. На современных процессорах разницы уже нет, поэтому в OpenRCT2 всё свели к 8-байтовым переменным, но в оригинале экономили каждый байт.
Второй приём — замена арифметики битовыми сдвигами. Вместо умножения на 4 в коде стоит сдвиг влево на две позиции, вместо деления на 8 — сдвиг вправо на три. Сдвиг намного дешевле для процессора. Интересна тут не сама техника, а то, как часто она применима: сдвигом можно умножать и делить только на степени двойки. То, что в коде это встречается постоянно, означает, что игровые формулы изначально проектировались под удобные числа. Представьте программиста, который просит геймдизайнера заменить 9,5 на 8, потому что так удобнее процессору. В обычной студии это невозможно. В RCT программист и дизайнер — один человек, и это открывает третий, самый глубокий слой оптимизаций.
Дизайн ради производительности. Логичный путь для парк-симулятора такой: гость выбирает аттракцион по своим предпочтениям и идёт к нему. С точки зрения техники это худший сценарий — поиск пути дорогая операция, а гнать его для тысяч агентов разом тяжело даже сегодня. Поэтому гости в RCT ходят по парку фактически вслепую: идут по дорожке, на развилке выбирают направление почти случайно, с парой правил против тупиков, и натыкаются на интересное по дороге. Это видно в игре: гость жалуется на голод, но не ищет ближайший ларёк, а просто бредёт, пока случайно не пройдёт мимо еды. Честный поиск пути всё же есть — для механика, идущего к сломанному аттракциону, или для гостя к выходу. Но и там стоит предохранитель.
🔘 У поиска пути есть жёсткий лимит глубины обхода сети дорожек, и при его достижении поиск просто сдаётся и возвращает неудачу.
🔘 По умолчанию гостю можно пройти лишь до глубины в 5 развилок. Когда гость жалуется, что не может найти выход, это буквально работа алгоритма, который мог бы искать дальше, но не стал ради кадров.
🔘 Механик важнее обычного гостя, ему лимит подняли до 8 развилок.
🔘 Гость, купивший карту парка в киоске, получает лимит 7 вместо 5, и ему легче найти выход. Техническое ограничение превратили в игровую механику.
Тем же принципом решена толкучка. Система столкновений и обхода для тысяч агентов убила бы фреймрейт, поэтому гости в RCT не сталкиваются и не избегают друг друга — на одной плитке дорожки их могут стоять хоть тысячи. Но они считают соседей: если рядом слишком людно, падает счастье и летит жалоба игроку. Для игрока результат тот же — приходится планировать дорожки, чтобы не было давки, — а расчёт на порядок дешевле. Вывод Тофуса: менять дизайн ради производительности кажется радикальным шагом, но при должном диалоге между кодом и геймдизайном это даёт выигрыш, которого не добьёшься никакой микрооптимизацией. Иногда лучшая оптимизация — это смелость сказать техническому вызову «нет».
Сохранять тем, кто любит истории про low-level инженерию, ценит дизайн, продиктованный железом, и хочет показать коллегам, что значит «оптимизировано до предела».
https://www.larstofus.com/the-gold-standard-of-optimization-a-look-under-the-hood-of-rollercoaster-tycoon
@prog_stuff
RollerCoaster Tycoon (1999) до сих пор называют эталоном оптимизации. Крис Сойер написал игру почти целиком на ассемблере и заставил процессоры конца девяностых тащить парки с тысячами посетителей без единой просадки кадра — то, с чем многие современные градостроительные симуляторы справляются хуже на железе в сотни раз мощнее. Ларс Тофус в блоге Larst Of Us разобрал, как это устроено. Исходников игры нет, но есть почти эквивалент — OpenRCT2, побайтовая фанатская переразработка на годах реверс-инжиниринга. По ней и видно, насколько агрессивно вылизан каждый кусок.
Первое, что бросается в глаза, это типы данных под деньги. Сойер не брал один универсальный тип на все случаи, а подбирал размер под максимально ожидаемое значение. Общая стоимость парка может быть огромной, поэтому под неё отведено 4 байта. А цена товара в ларьке заведомо маленькая, под неё хватает одного байта. На современных процессорах разницы уже нет, поэтому в OpenRCT2 всё свели к 8-байтовым переменным, но в оригинале экономили каждый байт.
Второй приём — замена арифметики битовыми сдвигами. Вместо умножения на 4 в коде стоит сдвиг влево на две позиции, вместо деления на 8 — сдвиг вправо на три. Сдвиг намного дешевле для процессора. Интересна тут не сама техника, а то, как часто она применима: сдвигом можно умножать и делить только на степени двойки. То, что в коде это встречается постоянно, означает, что игровые формулы изначально проектировались под удобные числа. Представьте программиста, который просит геймдизайнера заменить 9,5 на 8, потому что так удобнее процессору. В обычной студии это невозможно. В RCT программист и дизайнер — один человек, и это открывает третий, самый глубокий слой оптимизаций.
Дизайн ради производительности. Логичный путь для парк-симулятора такой: гость выбирает аттракцион по своим предпочтениям и идёт к нему. С точки зрения техники это худший сценарий — поиск пути дорогая операция, а гнать его для тысяч агентов разом тяжело даже сегодня. Поэтому гости в RCT ходят по парку фактически вслепую: идут по дорожке, на развилке выбирают направление почти случайно, с парой правил против тупиков, и натыкаются на интересное по дороге. Это видно в игре: гость жалуется на голод, но не ищет ближайший ларёк, а просто бредёт, пока случайно не пройдёт мимо еды. Честный поиск пути всё же есть — для механика, идущего к сломанному аттракциону, или для гостя к выходу. Но и там стоит предохранитель.
Тем же принципом решена толкучка. Система столкновений и обхода для тысяч агентов убила бы фреймрейт, поэтому гости в RCT не сталкиваются и не избегают друг друга — на одной плитке дорожки их могут стоять хоть тысячи. Но они считают соседей: если рядом слишком людно, падает счастье и летит жалоба игроку. Для игрока результат тот же — приходится планировать дорожки, чтобы не было давки, — а расчёт на порядок дешевле. Вывод Тофуса: менять дизайн ради производительности кажется радикальным шагом, но при должном диалоге между кодом и геймдизайном это даёт выигрыш, которого не добьёшься никакой микрооптимизацией. Иногда лучшая оптимизация — это смелость сказать техническому вызову «нет».
Сохранять тем, кто любит истории про low-level инженерию, ценит дизайн, продиктованный железом, и хочет показать коллегам, что значит «оптимизировано до предела».
https://www.larstofus.com/the-gold-standard-of-optimization-a-look-under-the-hood-of-rollercoaster-tycoon
@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
Larst Of Us
The gold standard of optimization: A look under the hood of RollerCoaster Tycoon
Due to some lucky circumstances, I recently had the chance to appear in one of the biggest German gaming podcasts, Stay Forever, to talk about the technology of RollerCoaster Tycoon (1999). It was …
❤3👍1
В блоге Альфа-Банка вышла статья о метриках в разработке. Команда перепробовала аж 7 штук и путём проб и ошибок собрала свой минимальный набор, который реально приносит пользу. Основой стала Cycle Time — она показывает, сколько времени задача провела внутри процесса разработки, от старта до релиза.
Метрик часто опасаются: если внедрить их неправильно или использовать как дубинку, цифры начинают подгонять, а толку — ноль. Как этого избежать и подобрать правильный набор показателей под себя — читайте в статье: https://tproger.ru/articles/kak-my-sbezhali-iz-kpi-karaoke-naw-bazovyj-minimum-metrik-kot
Метрик часто опасаются: если внедрить их неправильно или использовать как дубинку, цифры начинают подгонять, а толку — ноль. Как этого избежать и подобрать правильный набор показателей под себя — читайте в статье: https://tproger.ru/articles/kak-my-sbezhali-iz-kpi-karaoke-naw-bazovyj-minimum-metrik-kot
Tproger
Как мы сбежали из «KPI-караоке»: наш базовый минимум метрик, который реально работает
Разбор метрик разработки: почему мы отказались от 6 из 7 KPI, оставили Cycle Time и как внедрять метрики без демотивации команды.
❤1👍1
Сколько стоит прочитать одну страницу в 8 КБ из Postgres — трассировка по всем слоям кэшей
Свежий разбор, который хочется выдать каждому, кто проектирует базы «на глазок». Автор словил в продакшене инцидент с IOPS, воспроизвёл ту же патологию на домашнем сервере и померил, во сколько обходится чтение одной и той же страницы на каждом уровне: shared buffers, page cache операционки, локальный NVMe и сетевой диск AWS EBS.
Числа красивые своей наглядностью, каждый слой стоит примерно на порядок дороже предыдущего:
🔘 страница в shared buffers — около 1,1 мкс;
🔘 в page cache ОС — около 4 мкс;
🔘 холодное чтение с локального NVMe — около 78 мкс;
🔘 сетевой EBS в продакшене — около 497 мкс, в 124 раза дороже page cache.
Самая поучительная деталь — про порядок чтения. Те же 500 холодных страниц в отсортированном порядке (bitmap heap scan) читаются за 2,8 мс, а в случайном (index scan) — за 39,5 мс. Разница в 14 раз на ровно тех же данных, всю работу делает readahead ядра.
Сохранять бэкендерам и всем, кто хоть раз удивлялся, почему запрос на ноутбуке летает, а в облаке встаёт колом.
Полная статья: https://frn.sh/8kb-read/
@prog_stuff
Свежий разбор, который хочется выдать каждому, кто проектирует базы «на глазок». Автор словил в продакшене инцидент с IOPS, воспроизвёл ту же патологию на домашнем сервере и померил, во сколько обходится чтение одной и той же страницы на каждом уровне: shared buffers, page cache операционки, локальный NVMe и сетевой диск AWS EBS.
Числа красивые своей наглядностью, каждый слой стоит примерно на порядок дороже предыдущего:
Самая поучительная деталь — про порядок чтения. Те же 500 холодных страниц в отсортированном порядке (bitmap heap scan) читаются за 2,8 мс, а в случайном (index scan) — за 39,5 мс. Разница в 14 раз на ровно тех же данных, всю работу делает readahead ядра.
Сохранять бэкендерам и всем, кто хоть раз удивлялся, почему запрос на ноутбуке летает, а в облаке встаёт колом.
Полная статья: https://frn.sh/8kb-read/
@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1👍1
Софт рождается между коммитами — Zed представила DeltaDB, контроль версий для эпохи агентов
Команда редактора Zed считает, что Git перестал отражать то, как теперь пишется код: половина работы происходит в диалогах с агентами, а коммит видит только итоговый снимок. DeltaDB записывает каждую операцию между коммитами как отдельную дельту со стабильным идентификатором и сохраняет рядом разговор, который это изменение породил.
Что это даёт:
🔘 с любой строки кода можно перейти к диалогу, в котором она появилась, и ко всем последующим обсуждениям;
🔘 ссылки на код привязаны к дельтам, а не к номерам строк, поэтому не ломаются, когда код переезжает;
🔘 рабочие деревья построены на CRDT: несколько людей и агентов правят одни файлы на разных машинах без конфликтов;
🔘 коллега может подключиться к работе, поговорить с агентом и оставить пометки, не дожидаясь commit и push;
🔘 агенты получают контекст: могут «спросить» предыдущих агентов, почему код написан именно так.
Git при этом не выбрасывается — остаётся для CI и связи с внешним миром, просто перестаёт быть единственной точкой совместной работы. Бета обещана в ближайшие недели, открыт список ожидания.
Сохранять тем, кто много работает с кодящими агентами и уже ловил себя на том, что контекст решений теряется между сессиями.
Полная статья: https://zed.dev/blog/introducing-deltadb
@prog_stuff
Команда редактора Zed считает, что Git перестал отражать то, как теперь пишется код: половина работы происходит в диалогах с агентами, а коммит видит только итоговый снимок. DeltaDB записывает каждую операцию между коммитами как отдельную дельту со стабильным идентификатором и сохраняет рядом разговор, который это изменение породил.
Что это даёт:
Git при этом не выбрасывается — остаётся для CI и связи с внешним миром, просто перестаёт быть единственной точкой совместной работы. Бета обещана в ближайшие недели, открыт список ожидания.
Сохранять тем, кто много работает с кодящими агентами и уже ловил себя на том, что контекст решений теряется между сессиями.
Полная статья: https://zed.dev/blog/introducing-deltadb
@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Хватит использовать Conventional Commits — провокационное эссе с аргументами, которые сложно отмахнуть
Автор бьёт по стандарту, который многие команды внедрили не задумываясь. Главный тезис: Conventional Commits фокусируют на неважном и обесценивают важное. Тип коммита (
Аргументация по пунктам:
🔘 всем читателям истории важнее «где», чем «что за тип»: контрибьютор ищет изменения в конкретной подсистеме, дебажащий ищет по компоненту, дежурный при инциденте смотрит на область, где всплеск ошибок;
🔘 тип часто избыточен: в
🔘 обещания стандарта не выполняются: автогенерация changelog ломается на многокоммитных фичах и ревертах, автоопределение semver даёт ложные срабатывания, а триггерить CI по
🔘 ИИ-ассистенты по привычке генерируют Conventional Commits, чем разносят антипаттерн дальше.
Взамен предлагаются scoped commits: префикс с областью и описание. Это даже не новый стандарт — так десятилетиями живут Linux (
Текст вышел 5 июня и уже собрал жаркие обсуждения. Сохранять тем, кто пишет гайдлайны для команды: даже если останетесь на Conventional Commits, аргументы стоит знать.
Полная статья: https://sumnerevans.com/posts/software-engineering/stop-using-conventional-commits/
@prog_stuff
Автор бьёт по стандарту, который многие команды внедрили не задумываясь. Главный тезис: Conventional Commits фокусируют на неважном и обесценивают важное. Тип коммита (
fix, feat, chore) стоит на первом месте и обязателен, а scope — область, которую трогает коммит — опционален и прячется в скобках. По мнению автора, всё должно быть наоборот.Аргументация по пунктам:
fix(compiler): prevent SVG elements from being stripped и без префикса видно, что это багфикс;docs: в сообщении опасно — честнее смотреть на изменённые файлы;Взамен предлагаются scoped commits: префикс с областью и описание. Это даже не новый стандарт — так десятилетиями живут Linux (
i2c: virtio: mark device ready...), Git, Go (net/http/cookiejar: add godoc links), FreeBSD, Node.js и nixpkgs.Текст вышел 5 июня и уже собрал жаркие обсуждения. Сохранять тем, кто пишет гайдлайны для команды: даже если останетесь на Conventional Commits, аргументы стоит знать.
Полная статья: https://sumnerevans.com/posts/software-engineering/stop-using-conventional-commits/
@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
Семь ошибок в архитектурных диаграммах, которые делают почти все
Команда Ilograph собрала второй заход по антипаттернам системных диаграмм (в первой части было ещё семь, итого четырнадцать). Список из тех, где на каждом пункте узнаёшь свои схемы:
🔘 подписи типом вместо имени: на диаграмме «Amazon S3» и «AWS Lambda», и непонятно, какой именно бакет и какая функция. Лечится суффиксом типа: Orders Table, Results Bucket;
🔘 висящие ресурсы: компонент нарисован, но ни с чем не соединён, и его роль приходится угадывать;
🔘 «мастер-диаграмма»: попытка уместить всю систему в одну схему, где смешаны runtime-зависимости, DNS, CDN и деплой. Решение — несколько диаграмм с разных точек зрения;
🔘 синдром конвейера: поведение системы рисуют как поток слева направо, хотя реальные взаимодействия ходят туда-обратно. Для этого есть sequence-диаграммы;
🔘 бессмысленные анимации: мелькающие стрелки дублируют то, что и так видно, и нужны только для маркетинга;
🔘 fan trap: продюсеры и консьюмеры сходятся в одном брокере сообщений, и кто с кем реально общается — не видно. Лечится отрисовкой топиков внутри брокера;
🔘 вера, что ИИ построит качественную диаграмму из исходников: на выходе размытые схемы с галлюцинациями и теми же ошибками из пунктов выше, потому что модель не умеет стратегически решать, что включить, а что выкинуть.
Сохранять перед следующим дизайн-ревью: пройтись по списку и проверить свою схему по всем семи пунктам быстрее, чем потом объяснять её голосом.
Полная статья: https://www.ilograph.com/blog/posts/more-common-diagram-mistakes/
@prog_stuff
Команда Ilograph собрала второй заход по антипаттернам системных диаграмм (в первой части было ещё семь, итого четырнадцать). Список из тех, где на каждом пункте узнаёшь свои схемы:
Сохранять перед следующим дизайн-ревью: пройтись по списку и проверить свою схему по всем семи пунктам быстрее, чем потом объяснять её голосом.
Полная статья: https://www.ilograph.com/blog/posts/more-common-diagram-mistakes/
@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
В большинстве компаний 1С и облачная инфраструктура живут в параллельных мирах: DevOps смотрит в Grafana, финдиректор — в 1С, а когда падает оплата, все смотрят друг на друга. На самом деле подружить 1С с современными инструментами мониторинга вполне реально всего за один спринт. В блоге Centicore рассказали, как это сделать.
В статье разбирается, как вытащить метрики из 1С через OData без единой строчки кода, написать Prometheus Exporter на Python и собрать бизнес- и технические метрики на одном дашборде. А заодно — где интеграция обычно ломается и как это пережить.
В статье разбирается, как вытащить метрики из 1С через OData без единой строчки кода, написать Prometheus Exporter на Python и собрать бизнес- и технические метрики на одном дашборде. А заодно — где интеграция обычно ломается и как это пережить.
Tproger
Как связать дедовский 1С и модный Kubernetes в одном дашборде
Пошаговая интеграция 1С и Kubernetes через OData, Prometheus Exporter и Grafana — без консультантов и магии.
RCE, которую AMD не хотела чинить: история одного разбора
Автор разозлился на всплывающее консольное окно на игровом ПК, отследил его до AMD AutoUpdate и в наказание декомпилировал программу. Внутри нашлась цепочка на удалённое выполнение кода: список обновлений приходит по HTTPS, но ссылки на сами исполняемые файлы в нём — обычный HTTP, а проверки подписи нет вообще. Атакующий в той же сети подменяет ответ, и апдейтер скачивает и сразу запускает любой бинарник.
Как развивались события:
🔘 27 января — уязвимость найдена, 6 февраля — отчёт в AMD;
🔘 в тот же день AMD закрывает его со статусом «не будем чинить»: MITM-атаки вне скоупа их баг-баунти;
🔘 на следующий день после публикации блог-поста компания передумала и попросила пост убрать;
🔘 дальше четыре месяца продлений эмбарго: «затронуты ещё несколько инструментов», «клиенты просят время»;
🔘 9 июня, через 124 дня, эмбарго снято и присвоен CVE.
Детали финала достойны отдельного абзаца. Вместо криптографической подписи AMD добавила проверку CRC-32, которая от подмены не защищает. Выплата за находку — ноль долларов: формально вне скоупа. А эксплуатировать дыру всё это время было нельзя по смешной причине: апдейтер падал из-за другого, никем не замеченного бага с редиректом.
Сохранять тем, кто пишет автообновления (HTTPS и подпись бинарников обязательны), и тем, кто хочет понимать, как на самом деле выглядит ответственное разглашение.
Полная статья: https://mrbruh.com/amd2/
@prog_stuff
Автор разозлился на всплывающее консольное окно на игровом ПК, отследил его до AMD AutoUpdate и в наказание декомпилировал программу. Внутри нашлась цепочка на удалённое выполнение кода: список обновлений приходит по HTTPS, но ссылки на сами исполняемые файлы в нём — обычный HTTP, а проверки подписи нет вообще. Атакующий в той же сети подменяет ответ, и апдейтер скачивает и сразу запускает любой бинарник.
Как развивались события:
Детали финала достойны отдельного абзаца. Вместо криптографической подписи AMD добавила проверку CRC-32, которая от подмены не защищает. Выплата за находку — ноль долларов: формально вне скоупа. А эксплуатировать дыру всё это время было нельзя по смешной причине: апдейтер падал из-за другого, никем не замеченного бага с редиректом.
Сохранять тем, кто пишет автообновления (HTTPS и подпись бинарников обязательны), и тем, кто хочет понимать, как на самом деле выглядит ответственное разглашение.
Полная статья: https://mrbruh.com/amd2/
@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Почему случайные UUID в роли первичного ключа убивают вставки в SQLite
Разбор с бенчмарками и профилированием о том, как выбор типа первичного ключа меняет скорость записи в разы. Суть проблемы: первичный ключ задаёт физический порядок хранения строк в B-дереве. Случайный UUID4 означает вставки в случайные места дерева, а это бесконечные сплиты страниц и ребалансировки.
Автор вставляет 10 миллионов строк пакетами по миллиону и сравнивает:
🔘 обычный INTEGER-ключ: стабильные ~715 мс на миллион, эталон;
🔘 UUID4 с WITHOUT ROWID: первый миллион 2649 мс, десятый уже 12586 мс — деградация нелинейная, чем больше таблица, тем хуже, итог до 18 раз медленнее эталона;
🔘 UUID7 с WITHOUT ROWID: стабильные ~1250 мс на миллион без всякой деградации.
Весь фокус в том, что UUID7 содержит таймстемп в старших битах, поэтому новые ключи монотонно растут и ложатся в конец дерева, как автоинкремент. UUID4 при этом остаётся медленнее целого числа примерно на 70%: ключ занимает 16 байт против 8, строк на страницу помещается меньше.
Отдельный урок про WITHOUT ROWID: эта опция полезна, когда по первичному ключу часто ищут, но в паре со случайным UUID получается худшее из двух миров — данные лежат и в листьях, и в промежуточных узлах дерева, и ребалансировка дорожает максимально.
Выводы переносятся на любую БД с кластерным индексом, от MySQL InnoDB до SQL Server. Сохранять всем, кто сейчас выбирает схему ключей для нового сервиса.
Полная статья: https://andersmurphy.com/2026/06/05/the-perils-of-uuid-primary-keys-in-sqlite.html
@prog_stuff
Разбор с бенчмарками и профилированием о том, как выбор типа первичного ключа меняет скорость записи в разы. Суть проблемы: первичный ключ задаёт физический порядок хранения строк в B-дереве. Случайный UUID4 означает вставки в случайные места дерева, а это бесконечные сплиты страниц и ребалансировки.
Автор вставляет 10 миллионов строк пакетами по миллиону и сравнивает:
Весь фокус в том, что UUID7 содержит таймстемп в старших битах, поэтому новые ключи монотонно растут и ложатся в конец дерева, как автоинкремент. UUID4 при этом остаётся медленнее целого числа примерно на 70%: ключ занимает 16 байт против 8, строк на страницу помещается меньше.
Отдельный урок про WITHOUT ROWID: эта опция полезна, когда по первичному ключу часто ищут, но в паре со случайным UUID получается худшее из двух миров — данные лежат и в листьях, и в промежуточных узлах дерева, и ребалансировка дорожает максимально.
Выводы переносятся на любую БД с кластерным индексом, от MySQL InnoDB до SQL Server. Сохранять всем, кто сейчас выбирает схему ключей для нового сервиса.
Полная статья: https://andersmurphy.com/2026/06/05/the-perils-of-uuid-primary-keys-in-sqlite.html
@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
Andersmurphy
The perils of UUID primary keys in SQLite
A blog mostly about Clojure programming
👍1
CSS: какие части языка неустранимо плохие и как с ними жить
Разбор от Алекса Кладова (matklad, автор rust-analyzer) — взгляд бэкендера, которому пришлось стилизовать свой блог. Он разложил CSS на части, которые работают предсказуемо, и части, которые подведут в самый неожиданный момент, и для каждой плохой нашёл обходной путь.
Главные практические выводы:
🔘 первая строка любого CSS-файла —
🔘 вместо обёрток и div-супа — семантические теги
🔘 отступы между детьми удобно задавать через owl-селектор
🔘 явные media-запросы для простых страниц не нужны: flexbox и
🔘 браузерные дефолты — ловушка: проблема не в правиле, которое вы написали, а в правиле, на которое вы полагаетесь, не написав его;
🔘
Для блога автору хватило примерно 200 строк читаемого CSS без фреймворков.
Сохранять тем, кто не фронтендер, но периодически вынужден верстать: страницу проекта, документацию, личный блог.
Полная статья: https://matklad.github.io/2026/06/04/css-unavoidable-bad-parts.html
@prog_stuff
Разбор от Алекса Кладова (matklad, автор rust-analyzer) — взгляд бэкендера, которому пришлось стилизовать свой блог. Он разложил CSS на части, которые работают предсказуемо, и части, которые подведут в самый неожиданный момент, и для каждой плохой нашёл обходной путь.
Главные практические выводы:
* { box-sizing: border-box; }, иначе padding ломает размеры элементов;main, article, nav, details: с ними простой classless CSS работает сам;section > *+* { margin-top: 1rem; } — родитель контролирует расстояния, дети ни о чём не знают;max-width на главной колонке дают отзывчивость бесплатно;font-size задаёт размер виртуальной коробки вокруг глифа, а не сам глиф — выровнять два шрифта помогает font-size-adjust.Для блога автору хватило примерно 200 строк читаемого CSS без фреймворков.
Сохранять тем, кто не фронтендер, но периодически вынужден верстать: страницу проекта, документацию, личный блог.
Полная статья: https://matklad.github.io/2026/06/04/css-unavoidable-bad-parts.html
@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2👍1
Как мы проскочили путь от первого iPhone и сложной разработки под мобильные устройства до эпохи ИИ? Что случилось и к чему это привело — в третьей части цикла об истории российского IT.
Мобильный бум застал индустрию врасплох: было непонятно, как адаптировать сайты под маленькие экраны и что делать со слабой связью. Решением стали нативные приложения — их начали разрабатывать многие компании. Так мы пришли к эпохе супераппов, где собрано всё и сразу.
Приложений, проектов и стартапов становилось больше — начался расцвет российского IT. Но разработчиков не хватало, и на сцену вышли курсы, школы и онлайн-уроки. Желающих войти в профессию оказалось огромное количество, и рынок быстро перегрелся. Теперь новичков заменяет ИИ, а найти работу — задача со звёздочкой. Сегодня гонка за лучшими программистами превратилась в гонку ИИ-инфраструктур.
Так решения порождали новые проблемы, а российская IT-индустрия вышла на новый уровень сложности. Подробнее — в материале на Tproger.
Мобильный бум застал индустрию врасплох: было непонятно, как адаптировать сайты под маленькие экраны и что делать со слабой связью. Решением стали нативные приложения — их начали разрабатывать многие компании. Так мы пришли к эпохе супераппов, где собрано всё и сразу.
Приложений, проектов и стартапов становилось больше — начался расцвет российского IT. Но разработчиков не хватало, и на сцену вышли курсы, школы и онлайн-уроки. Желающих войти в профессию оказалось огромное количество, и рынок быстро перегрелся. Теперь новичков заменяет ИИ, а найти работу — задача со звёздочкой. Сегодня гонка за лучшими программистами превратилась в гонку ИИ-инфраструктур.
Так решения порождали новые проблемы, а российская IT-индустрия вышла на новый уровень сложности. Подробнее — в материале на Tproger.
Tproger
От первого iPhone до ИИ: как эволюционировало IT с 2010-х до сегодняшнего дня
История российского IT: от смартфонов и супераппов до бум онлайн-образования и эпохи нейросетей. Как технологии меняли индустрию за 15 лет.
🤗2
Algorithm Visualizer — сайт, где 30+ алгоритмов разобраны пошаговой анимацией
Открытый React-проект, который превращает сухие учебники по алгоритмам в живые картинки: на каждом шаге видно состояние структуры данных, активную строку кода и пояснение, что сейчас происходит. Проект живой, в июне завезли крупное обновление.
Что внутри:
🔘 поиск пути и обходы графов: BFS, DFS, Dijkstra, Bellman-Ford;
🔘 остовные деревья Краскала и Прима, компоненты связности, потоки в сетях (Edmonds-Karp, Ford-Fulkerson);
🔘 сортировки, бинарное дерево поиска, связные списки, дерево рекурсии;
🔘 классика собеседований и олимпиад: N-Queens, выпуклая оболочка, машина Тьюринга.
Июньское обновление добавило визуализатор связных списков, рабочее пространство для обходов графа, кратчайшие пути с остовными деревьями и переиспользуемый SVG-компонент дерева с BST.
Работает прямо в браузере, ничего ставить не нужно. Сохранять студентам перед сессией, всем, кто готовится к алгоритмическим секциям собеседований, и менторам — объяснять джуну Дейкстру по анимации сильно проще, чем по псевдокоду.
Полная ссылка: https://tamimehsan.github.io/AlgorithmVisualizer/
@prog_stuff
Открытый React-проект, который превращает сухие учебники по алгоритмам в живые картинки: на каждом шаге видно состояние структуры данных, активную строку кода и пояснение, что сейчас происходит. Проект живой, в июне завезли крупное обновление.
Что внутри:
Июньское обновление добавило визуализатор связных списков, рабочее пространство для обходов графа, кратчайшие пути с остовными деревьями и переиспользуемый SVG-компонент дерева с BST.
Работает прямо в браузере, ничего ставить не нужно. Сохранять студентам перед сессией, всем, кто готовится к алгоритмическим секциям собеседований, и менторам — объяснять джуну Дейкстру по анимации сильно проще, чем по псевдокоду.
Полная ссылка: https://tamimehsan.github.io/AlgorithmVisualizer/
@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2👍1
Сжать баг до минимального примера автоматически: про недооценённые test-case reducers
Когда баг воспроизводится на огромном входе — файле, программе, последовательности действий — стандартный совет «сделайте минимальный пример» звучит легко, а руками делается мучительно. Лори Тратт напоминает про инструменты, которые делают это сами: test-case reducers берут падающий вход и ужимают его, часто на 95-99%, до состояния, где удалить уже нечего.
Ключевая идея — reducer ничего не знает про ваш язык и формат. Ему нужен только оракул: функция, которая отвечает «да, этот вход всё ещё интересен», то есть баг по-прежнему воспроизводится. Всё остальное — перебор и выбрасывание кусков.
Что полезно знать:
🔘 reducer языконезависим: тот же инструмент сжимает и C-программу, и JSON, и лог действий, лишь бы был тест на «интересность»;
🔘 написать хороший тест на интересность сложнее, чем кажется: легко получить переусушку, когда вход схлопывается в другой баг, не тот, что вы ловите;
🔘 скорость этого теста решает всё: reducer вызывает его тысячи раз, поэтому его выгодно делать максимально дешёвым;
🔘 сжимать можно не только по длине входа, но и по другим метрикам — длине трейса, числу инструкций, частоте срабатывания ошибки;
🔘 есть приёмы и для недетерминированных багов, которые воспроизводятся через раз.
Сохранять всем, кто хоть раз убил полдня на ручное вырезание строк из репродукции. Навык языконезависимый и не устаревает: дешёвый минимальный пример экономит часы на каждом нетривиальном баге.
Полная статья: https://tratt.net/laurie/blog/2026/test_case_reducers_are_underappreciated_debugging_tools.html
@prog_stuff
Когда баг воспроизводится на огромном входе — файле, программе, последовательности действий — стандартный совет «сделайте минимальный пример» звучит легко, а руками делается мучительно. Лори Тратт напоминает про инструменты, которые делают это сами: test-case reducers берут падающий вход и ужимают его, часто на 95-99%, до состояния, где удалить уже нечего.
Ключевая идея — reducer ничего не знает про ваш язык и формат. Ему нужен только оракул: функция, которая отвечает «да, этот вход всё ещё интересен», то есть баг по-прежнему воспроизводится. Всё остальное — перебор и выбрасывание кусков.
Что полезно знать:
Сохранять всем, кто хоть раз убил полдня на ручное вырезание строк из репродукции. Навык языконезависимый и не устаревает: дешёвый минимальный пример экономит часы на каждом нетривиальном баге.
Полная статья: https://tratt.net/laurie/blog/2026/test_case_reducers_are_underappreciated_debugging_tools.html
@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Forwarded from Типичный программист
Разработчик заменил 3 ГБ SQLite на десяток мегабайт FST и не потерял в скорости
У финнов есть слово opiskelijassammekin, и если вы не носитель, разобрать его вручную — то ещё удовольствие. Проект Taskusanakirja как раз помогает: вводишь приставку, а словарь ищет финско-английские пары на лету. Раньше под это дело автор держал 3 ГБ SQLite и упирался в размер.
В итоге он перешёл на FST (finite state transducer), статичную структуру данных для префиксного поиска. Бинарник сжался до десятка мегабайт, а отклик остался таким, что глаз не заметит.
Цепляет не столько цифрой, сколько подходом: вместо универсальной базы используется узкая структура, которая делает ровно то, что нужно, и не жрёт лишнего. Хороший напоминание, что иногда оптимизация заключается не в ускорении запросов, а в отказе от лишнего инструмента.
У финнов есть слово opiskelijassammekin, и если вы не носитель, разобрать его вручную — то ещё удовольствие. Проект Taskusanakirja как раз помогает: вводишь приставку, а словарь ищет финско-английские пары на лету. Раньше под это дело автор держал 3 ГБ SQLite и упирался в размер.
В итоге он перешёл на FST (finite state transducer), статичную структуру данных для префиксного поиска. Бинарник сжался до десятка мегабайт, а отклик остался таким, что глаз не заметит.
Цепляет не столько цифрой, сколько подходом: вместо универсальной базы используется узкая структура, которая делает ровно то, что нужно, и не жрёт лишнего. Хороший напоминание, что иногда оптимизация заключается не в ускорении запросов, а в отказе от лишнего инструмента.
til.andrew-quinn.me
Replacing a 3 GB SQLite database with a 10 MB FST (finite state transducer) binary
Note for
numberphiles:
all numbers have been rounded to their first significant
digit, because I’m a fan of Rob Eastaway’s
“zequals” method
of getting to the point when it comes to estimation. It’s much
more valuable to walk away with the heuristic “some…
numberphiles:
all numbers have been rounded to their first significant
digit, because I’m a fan of Rob Eastaway’s
“zequals” method
of getting to the point when it comes to estimation. It’s much
more valuable to walk away with the heuristic “some…
❤1👍1
p99 0 мс на автодополнение 240 миллионов доменов
Автор поставил себе дерзкую цель: показывать подсказки раньше, чем пользователь успеет отпустить клавишу. Задержку он меряет от момента keyUp до готового результата и закладывает бюджет p99 в 121 мс на два нажатия с паузой между ними. Чтобы в него уложиться, выдача должна быть готова почти мгновенно.
Архитектура делится на две части по распределению запросов:
🔘 голова, миллион самых частых доменов из списка Tranco, лежит в памяти как символьный trie с заранее посчитанным топ-8 для каждого префикса;
🔘 хвост, все 240 миллионов доменов из CZDS, лежит на SSD как memory-mapped блочный индекс с дельта-сжатием: 27 МБ оглавления в памяти и 2,5 ГБ на диске;
🔘 большинство запросов к API отвечают за 2 мс, на нагрузке 1600 запросов в секунду p99 связки nginx и API держится около 15 мс;
🔘 оставшаяся задержка упирается в сетевой путь через Cloudflare, поэтому для дальних регионов нужна геобалансировка.
По дороге видно, как требование «мгновенно» раскладывается на конкретные структуры данных и бюджеты по миллисекундам.
Сохранять тем, кто проектирует поиск и автодополнение под нагрузкой и любит, когда задержку считают по слоям.
Полная статья: https://ruurtjan.com/articles/p99-0ms-autocomplete-for-240-million-domain-names
@prog_stuff
Автор поставил себе дерзкую цель: показывать подсказки раньше, чем пользователь успеет отпустить клавишу. Задержку он меряет от момента keyUp до готового результата и закладывает бюджет p99 в 121 мс на два нажатия с паузой между ними. Чтобы в него уложиться, выдача должна быть готова почти мгновенно.
Архитектура делится на две части по распределению запросов:
По дороге видно, как требование «мгновенно» раскладывается на конкретные структуры данных и бюджеты по миллисекундам.
Сохранять тем, кто проектирует поиск и автодополнение под нагрузкой и любит, когда задержку считают по слоям.
Полная статья: https://ruurtjan.com/articles/p99-0ms-autocomplete-for-240-million-domain-names
@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2👍1
Сжать GIF без потерь полным перебором: история ZGIF
GIF внутри использует LZW, а не DEFLATE, и это влияет на то, как его сжимать. Существующий flexiGIF уже умеет гибкий разбор с заглядыванием вперёд, но иногда делает хуже: занятый слот в словаре потом аукается. Автор задался вопросом, какой LZW-поток для картинки минимален в принципе, и написал ZGIF, который ищет этот минимум полным перебором. По духу это Zopfli, только для LZW.
Путь к рабочей версии занял несколько подходов, от поиска A* через динамическое программирование к гибриду с отсечением:
🔘 первая реализация на Python сжимала картинку 16 на 16 пикселей, всего 256 байт, за 30 минут;
🔘 после оптимизаций то же самое стало занимать 4 минуты;
🔘 с отсечением и заглядыванием на один шаг скорость упала до 4 секунд;
🔘 результат при этом всё равно плотнее, чем у существующих инструментов.
Сохранять тем, кто любит алгоритмы сжатия и истории про то, как наивная идея «давайте переберём всё» доводится до практичной скорости.
Полная статья: https://blog.arusekk.pl/posts/lossless-gif-recompression/
@prog_stuff
GIF внутри использует LZW, а не DEFLATE, и это влияет на то, как его сжимать. Существующий flexiGIF уже умеет гибкий разбор с заглядыванием вперёд, но иногда делает хуже: занятый слот в словаре потом аукается. Автор задался вопросом, какой LZW-поток для картинки минимален в принципе, и написал ZGIF, который ищет этот минимум полным перебором. По духу это Zopfli, только для LZW.
Путь к рабочей версии занял несколько подходов, от поиска A* через динамическое программирование к гибриду с отсечением:
Сохранять тем, кто любит алгоритмы сжатия и истории про то, как наивная идея «давайте переберём всё» доводится до практичной скорости.
Полная статья: https://blog.arusekk.pl/posts/lossless-gif-recompression/
@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3❤🔥1👍1
Похвала memcached: зачем намеренно держать кеш простым
Автор объясняет, почему в новых проектах снова берёт memcached вместо Redis. Redis он плохим не называет. Просто напоминает, что у простого инструмента есть свои сильные стороны, про которые многие забыли.
Главные мысли разбора:
🔘 Redis легко перерастает из кеша в самодельную базу: положить данные через
🔘 у memcached нет персистентности на диск, и это сделано намеренно: его можно гонять как нагрузку без состояния и не думать о сохранности;
🔘 клиентские библиотеки memcached прощают сбои: если сервер упал,
🔘 кластеризация живёт на стороне клиента через хеширование ключей по нескольким адресам, упавшая нода выводится из ротации;
🔘 автор спокойно поднимает десятки инстансов по 64 МБ почти без накладных расходов.
Сохранять тем, кто выбирает кеш для веба и заодно хочет перечитать аргумент против того, чтобы кеш медленно превращался в критичное хранилище состояния.
Полная статья: https://jchri.st/blog/in-praise-of-memcached/
@prog_stuff
Автор объясняет, почему в новых проектах снова берёт memcached вместо Redis. Redis он плохим не называет. Просто напоминает, что у простого инструмента есть свои сильные стороны, про которые многие забыли.
Главные мысли разбора:
SET проще, чем сделать INSERT, и команда постепенно перестаёт относиться к нему как к временному кешу;get возвращает пустоту, и приложение просто идёт в основной источник данных;Сохранять тем, кто выбирает кеш для веба и заодно хочет перечитать аргумент против того, чтобы кеш медленно превращался в критичное хранилище состояния.
Полная статья: https://jchri.st/blog/in-praise-of-memcached/
@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
MinIO на staging: собственное S3-хранилище вместо облачного счёта
Казалось бы, облачное S3-хранилище на staging — очевидный выбор. Но аватары, документы, отчёты и записи звонков там не удаляют, SLA не нужен, а счёт растёт за хранение и трафик. В гайде разбирают, как поднять MinIO на том же VPS, где крутится staging.
MinIO реализует API Amazon S3 и понимает те же SDK и presigned URL, но стоит ровно столько, сколько диск сервера. Код клиента не меняется: меняются только эндпоинт, регион, ключи и флаг
Сохраните, если устали платить за тестовые артефакты или заметили, что staging тестирует не тот путь загрузки, что прод.
Казалось бы, облачное S3-хранилище на staging — очевидный выбор. Но аватары, документы, отчёты и записи звонков там не удаляют, SLA не нужен, а счёт растёт за хранение и трафик. В гайде разбирают, как поднять MinIO на том же VPS, где крутится staging.
MinIO реализует API Amazon S3 и понимает те же SDK и presigned URL, но стоит ровно столько, сколько диск сервера. Код клиента не меняется: меняются только эндпоинт, регион, ключи и флаг
forcePathStyle. Контейнер поднимается за 10–15 минут, HTTPS отдаётся обратному прокси с Let’s Encrypt, а приложение получает отдельного пользователя с политикой только на нужный бакет.Сохраните, если устали платить за тестовые артефакты или заметили, что staging тестирует не тот путь загрузки, что прод.
Git-сервер без диска: как объектное хранилище научили говорить по git
Git-репозиторий под капотом это объектное хранилище: коммиты, деревья и сами файлы лежат как сжатые объекты с адресацией по содержимому, а ветки и теги это крошечные изменяемые указатели на них. Обычно git-сервер держит всё это на локальной файловой системе одной машины, и она становится единой точкой отказа. Автор решил проверить, что будет, если направить git-сервер прямо в бакет объектного хранилища, без диска, без бинарника git и без базы данных.
Получился objgit, один бинарник, который хранит репозитории в облачном бакете и говорит по трём транспортам: HTTP, классический git:// и SSH. Внутри он опирается на go-git, чистую реализацию протоколов git на Go, и на billy, файловую абстракцию, которую автор натянул на объектное хранилище, чтобы go-git не заметил подмены.
Самое предметное в статье это грабли латентности, разобранные по числу запросов:
🔘 push пакета из 100 тысяч объектов разворачивался в 200 тысяч обращений к хранилищу, по одному stat и write на каждый объект, и при задержке около 10 мс это полчаса ожидания;
🔘 клон простого репозитория из 318 объектов с пакетом в 200 КиБ до починки кеша делал больше 8500 вызовов GetObject;
🔘 поиск объектов по двухсимвольным префиксам каталога давал до 256 вызовов листинга бакета за один клон;
🔘 ошибка в кеше приводила к тысячам фоновых листингов каждые 30 секунд в течение 10 минут;
🔘 pack-файлы неизменны и адресуются по содержимому, поэтому их можно держать в локальном кеше без инвалидации: первый запрос медленный, дальше скорость файловой системы;
🔘 атомарное обновление веток автор делает через расширение RenameObject, переименование объекта за один запрос к хранилищу.
Сохранять тем, кто строит поверх объектных хранилищ или любит истории про то, как привычный инструмент ведёт себя на непривычном бэкенде и во что упирается по числу запросов.
Полная статья: https://www.tigrisdata.com/blog/objgit/
@prog_stuff
Git-репозиторий под капотом это объектное хранилище: коммиты, деревья и сами файлы лежат как сжатые объекты с адресацией по содержимому, а ветки и теги это крошечные изменяемые указатели на них. Обычно git-сервер держит всё это на локальной файловой системе одной машины, и она становится единой точкой отказа. Автор решил проверить, что будет, если направить git-сервер прямо в бакет объектного хранилища, без диска, без бинарника git и без базы данных.
Получился objgit, один бинарник, который хранит репозитории в облачном бакете и говорит по трём транспортам: HTTP, классический git:// и SSH. Внутри он опирается на go-git, чистую реализацию протоколов git на Go, и на billy, файловую абстракцию, которую автор натянул на объектное хранилище, чтобы go-git не заметил подмены.
Самое предметное в статье это грабли латентности, разобранные по числу запросов:
Сохранять тем, кто строит поверх объектных хранилищ или любит истории про то, как привычный инструмент ведёт себя на непривычном бэкенде и во что упирается по числу запросов.
Полная статья: https://www.tigrisdata.com/blog/objgit/
@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
VPS vs VDS vs виртуальный хостинг: что выбрать в 2026
Часто сервер выбирают по цене, а потом упираются в нехватку ресурсов, гибкости или поддержки. И почти никто не знает главного: VPS и VDS — это в большинстве случаев одно и то же, разница только в названии. Реально выбор идёт между хостингом (провайдер всё настроил, но конфигурация ограничена) и изолированным сервером с root-доступом.
В подборке 6 провайдеров под разные сценарии: от старта на виртуальном хостинге за ~123 рубля в месяц до VPS с зарубежными локациями. Внутри реальные цены, лимиты, условия по бэкапам, тестовым периодам и подсказки как сделать правильный выбор для своего случая.
Часто сервер выбирают по цене, а потом упираются в нехватку ресурсов, гибкости или поддержки. И почти никто не знает главного: VPS и VDS — это в большинстве случаев одно и то же, разница только в названии. Реально выбор идёт между хостингом (провайдер всё настроил, но конфигурация ограничена) и изолированным сервером с root-доступом.
В подборке 6 провайдеров под разные сценарии: от старта на виртуальном хостинге за ~123 рубля в месяц до VPS с зарубежными локациями. Внутри реальные цены, лимиты, условия по бэкапам, тестовым периодам и подсказки как сделать правильный выбор для своего случая.
Tproger
VPS vs VDS vs виртуальный хостинг: что выбрать в 2026
Сравнили VPS, VDS и виртуальный хостинг: чем отличаются, кому что подходит и сколько стоит. Подборка провайдеров с ценами и условиями.