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 и виртуальный хостинг: чем отличаются, кому что подходит и сколько стоит. Подборка провайдеров с ценами и условиями.