Сохранёнки программиста
6.59K subscribers
1.14K photos
59 videos
10 files
1.78K links
Заметки и ссылки на будущее, чтобы изучить когда будет время.

Разместить рекламу: @tproger_sales_bot

Правила общения: https://tprg.ru/rules

Другие каналы: @tproger_channels

Другие наши проекты: https://tprg.ru/med
Download Telegram
Forwarded from Типичный программист
Откуда в России взялись программисты — история, которую вам не рассказывали

Если вы думаете, что российский IT начался с нулевых — нет. Всё началось на несколько десятилетий раньше, в закрытых НИИ и институтских подвалах.

В конце 1940-х Советскому Союзу понадобились вычислительные машины — моделировать ядерные реакции и считать ракетные траектории вручную было нереально. Учёный Сергей Лебедев построил первую советскую ЭВМ, а потом серию БЭСМ. Пиковая модель, БЭСМ-6, выпускалась почти 20 лет — именно на ней учили программированию в лучших технических вузах.

Культура, сложившаяся в условиях жёстких ограничений, никуда не исчезла. Она и стала фундаментом для Яндекса, Контура и всего остального российского бигтеха.

Читайте все 7 фактов на Tproger

@tproger
Читайте также в VK, Max и Дзен
👍2
Современные CPU ненавидят непредсказуемые условные переходы. Если данные случайные, branch predictor постоянно ошибается, и процессор сбрасывает pipeline снова и снова.

Пример из статьи: фильтруем массив, оставляя элементы меньше 500.

Классический подход с if:

if (numbers[i] < 500) {
small_numbers[j] = numbers[i];
j += 1;
}


Результат на Apple M1: 0,329 сек за 1000 итераций.

Branchless версия — без ветвления, unconditional store + conditional increment:

small_numbers[j] = numbers[i];
j += (numbers[i] < 500);


Результат: 0.036 сек. Разница в 9 раз.

На ассемблере вместо условного b.gt (branch if greater) используется cinc на ARM или setle на x86 — инкрементируем индекс, только если условие выполнено. Никаких прыжков, pipeline работает на полную.

Почему компилятор не делает это сам? Он не знает природу данных. Если почти все элементы проходят фильтр, branch predictor почти всегда прав, и if версия быстрее. А unconditional write может быть небезопасен — например, если за границей буфера лежит чужая память.

Интересный нюанс: branch predictor имеет ограниченную «память». На массиве из 10K элементов gap исчезает, потому что CPU запоминает паттерн. На 100K — predictior переполняется, и branchless выигрывает снова.

Quicksort, кстати, идеально ложится на branchless: партиционирование вокруг pivot — это ровно та задача, где ветвление убивает производительность.

Полная статья: https://easylang.online/blog/branchless

@prog_stuff
2👍1
Microsoft выложила в open source самый ранний известный исходный код DOS — ядро 86-DOS 1.00, несколько development-снапшотов PC-DOS 1.00 и классические утилиты вроде CHKDSK.

Исторический контекст: Tim Paterson написал 86-DOS (тогда ещё QDOS — «quick and dirty operating system») для Intel 8086-компьютера от Seattle Computer Products. Microsoft лицензировала его для IBM PC 5150, выкупила права, переименовала в MS-DOS — и запустила эпоху PC.

Релиз позволяет посмотреть, как выглядела самая ранняя версия системы, которая стала фундаментом для десятилетий доминирования Microsoft на рынке персональных компьютеров.

Полная статья: https://arstechnica.com/gadgets/2026/04/microsoft-open-sources-the-earliest-dos-source-code-discovered-to-date

@prog_stuff
❤‍🔥2👍1
Как именно контейнеры создают иллюзию полноценной Linux-системы внутри, используя только базовые инструменты Linux: unshare, mount и pivot_root.

Что разбирается в статье:

Mount namespace — почему это фундамент изоляции, а PID, cgroup, UTS и network играют второстепенные роли.

Mount propagation — как mount-события распространяются между namespaces и почему просто unshare недостаточно.

pivot_root — как меняем корневую файловую систему процесса, чтобы он видел только то, что ему положено.

— Собираем вручную Docker-подобный контейнер, который запускается стандартными командами Linux.

Полная статья:
https://labs.iximiuz.com/tutorials/container-filesystem-from-scratch

@prog_stuff
3👍1
C3 — системный язык в традициях C — пять лет использовал unsigned типы для размеров и индексов, как C, C++, Rust и Zig. Казалось логичным: размер не может быть отрицательным. Но на практике это порождало классические баги: бесконечные циклы при декременте, сломанные сравнения при смешивании signed и unsigned, неявные конвертации, которые превращали -1 в огромное положительное число.

Точкой перелома стал невинный пример (foo + a) % 2. В C3 операция int + uint продвигалась в signed, что чаще работало правильно. Но если foo оказывался больше INT_MAX, результат становился непредсказуемым. Проблема не в сложности исправления, а в том, что это неожиданно: везде «просто работало», а тут вдруг ломается.

Ещё один показательный случай — кольцевой буфер. С signed типами ((start + offset) % length + length) % length корректно обрабатывает отрицательный offset. С unsigned та же формула молча даёт неправильный результат, и компилятор не подскажет, что offset_back обработан неверно.

Автор языка отмечает, что Java в 90-х полностью отказалась от unsigned типов, а Go — язык низкого уровня от разработчиков, прекрасно знавших цену unsigned, — изначально выбрал signed размеры. Границы unsigned (0 и 4 млрд для 32-бит) лежат критически близко к рабочему диапазону, тогда как у signed опасная зона — где-то в районе ±2 млрд. Переполнение unsigned не бросается в глаза: оно даёт вполне правдоподобное число, просто неправильное.

После перехода на signed тип sz (вместо usz) код оказался проще и очевиднее. Неявные конвертации между signed и unsigned убраны полностью. Автор признаётся, что привычка использовать unsigned была настолько глубоко внутренней, что переход казался «запрещённым» — но данные оказались неумолимыми.

Полная статья: https://c3-lang.org/blog/unsigned-sizes-a-five-year-mistake/

@prog_stuff
1👍1
Автор финско-английского словаря Taskusanakirja рассказал, как сжал 3-гигабайтную SQLite-базу до 10-мегабайтного бинарника.

Проблема была в финском языке — он агглютинативный, у одного слова может быть больше ста форм с разными окончаниями. Trie, который использовался для поиска по префиксам, справлялся с 400 тысячами слов (~50 МБ), но отказался масштабироваться на десятки миллионов форм. Временный костыль — SQLite с полнотекстовым поиском на 3 ГБ, с которым нужно было таскать трёхгигабайтную загрузку.

Решение — finite state transducer (FST) из Rust-крейта fst от BurntSushi. FST, в отличие от trie, сжимает и суффиксы тоже, а для финского с его повторяющимися окончаниями это идеально. Итог: 10 МБ вместо 3 ГБ, сжатие в 300 раз, и весь словарь теперь помещается в один статический бинарник.

Полная версия: https://til.andrew-quinn.me/posts/replacing-a-3-gb-sqlite-database-with-a-7-mb-fst-finite-state-trandsucer-binary/

@prog_stuff
👍2
Страуструп в своём FAQ отвечает на вопрос «Как бороться с утечками памяти?» — коротко: «Пишите код, в котором их нет».

Если new, delete и арифметика указателей разбросаны по всей кодовой базе, рано или поздно вы ошибётесь — сложность превысит усилия, которые можете себе позволить. Решение — прятать выделение и освобождение памяти внутри управляемых типов: контейнеры (vector, string) сами следят за своей памятью. Страустроп приводит пример программы без единого явного управления памятью, макросов, кастов и проверок переполнения.

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

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

Полная версия: https://www.stroustrup.com/bs_faq2.html#memory-leaks

@prog_stuff
👍3
Vite+ — один CLI вместо разрозненного стека

Исчерпывающий гайд по инструменту от VoidZero: один бинарник vp заменяет пять отдельных конфигов (Vite, Vitest, Oxlint, Oxfmt, Rolldown, Vite Task и управление версиями Node.js).

Раньше всё это жило в разных файлах: .eslintrc, .prettierrc, vitest.config.ts, .nvmrc. Теперь всё в одном vite.config.ts. vp check запускает форматирование, линтинг и типы разом. vp env заменяет NVM. Vite Task работает как кэшированный аналог Turborepo для монорепо.

Гайд разбирает каждый компонент: где Vite+ хорошо подходит (новые проекты, стандартный стек) и где нужна осторожность, например в production-базах с кастомными ESLint-плагинами.

Читать полный гайд, чтобы понять, стоит ли переезжать.
👍1
Как российская антивирусная индустрия выросла из дискет

На Tproger вышла вторая часть истории российского IT, про 90-е и нулевые. Один из больших разделов — про то, как защита от вирусов из академического побочного проекта превратилась в экспортную технологию.

В начале 90-х вирусы расползались через дискеты: принесли программу, заодно принесли вирус. Чем больше компьютеров появлялось в офисах и институтах, тем быстрее расходились заражённые файлы.

Первой отечественной попыткой был Tadpole, затем антивирусный сканер Tornado, которые потом объединились в Spider's Web. В 1993 году появился Dr.Web, а в 1994-м вышла его первая коммерческая версия.

Параллельно Евгений Касперский после работы в НИИ Министерства обороны ушёл в коммерческий IT, занимался антивирусами в КАМИ и в итоге собрал собственную фирму. Самое интересное случилось в 1996–1997: команда договорилась с иностранными вендорами, и зарубежные антивирусные продукты стали использовать российский движок внутри. Технология заработала на экспорт раньше, чем большая часть индустрии.

В этом же материале: про Контур и переход налоговой на дискеты, рождение Rambler и Яндекса, дефолт 1998 года и появление первых онлайн-банков.

Полная статья: https://tproger.ru/articles/kakim-bylo-it-v-90-h-i-nulevyh-modemy-kompy-defolt-i-pervye-o

@prog_stuff
1👍1
Саймон Уиллисон выступил на PyCon US 2026 с пятиминутным докладом про последние полгода в LLM, а потом разложил всю презентацию с комментариями к каждому слайду. Получился сжатый, но плотный обзор с ноября 2025 по май 2026.

Главная мысль: ноябрь 2025 года стал точкой перелома, особенно для агентов-программистов. До ноября они «часто работают». После ноября они «работают почти всегда» и могут стать основным инструментом, не отнимая половину времени на правку их ошибок.

Условное звание «лучшей модели» сменило хозяина пять раз за полгода: Claude Sonnet 4.5, потом GPT-5.1, дальше Gemini 3, GPT-5.1 Codex Max, и наконец Anthropic вернул лидерство с Opus 4.5. Уиллисон тестирует это всё на личном бенчмарке «сгенерируй SVG пеликана на велосипеде»: задача, под которую ни одна лаборатория модели не обучает.

Второй большой тренд: модели с открытыми весами выросли быстрее ожиданий. Gemma 4 от Google, крупнейшая серия с открытыми весами от американской лаборатории. GLM-5.1 от китайской GLM, открытая модель на 1,5 ТБ. И Qwen3.6-35B-A3B на 20,9 ГБ запускается на ноутбуке Уиллисона и рисует пеликана лучше, чем Claude Opus 4.7.

Февральская часть посвящена «эпохе Claws»: после OpenClaw и подобных персональных ИИ-агентов в индустрии прижился общий термин Claws. Mac Mini начали раскупать в Силиконовой долине именно под локальный запуск этих агентов.

Полный разбор со слайдами и оригинальными подписями: https://simonwillison.net/2026/May/19/5-minute-llms/

@prog_stuff
👍1👌1🤪1
Как ломаются мобильные приложения: пять багов на стыке систем

Разбор кейсов из практики мобильного тестирования. Общее у всех одно: формально каждая часть системы работала правильно, а баг появлялся там, где две части впервые встречались с реальными данными и железом.

Перечислять конкретные кейсы не буду, лучше сразу статью глянуть: https://tproger.ru/articles/kak-lomayutsya-mobilnye-prilozheniya

@prog_stuff
👍2
Lock-free очередь на C++ с нуля — подробный разбор того, как собрать MPMC-очередь, которая обгоняет std::queue под std::mutex в восемь раз при 16 потоках.

Автор идёт от наивной реализации к финальной и на каждом шаге объясняет, что и почему ломается:

🔘mutex-вариант разваливается из-за context switch в ядре;
🔘наивный CAS-подход спотыкается о ABA и use-after-free;
🔘батчинг по 1024 слота на узел убирает аллокатор с горячего пути и чинит cache locality;
🔘hazard pointers безопасно освобождают память без локов;
🔘thread-local кэш узлов окончательно убирает кучу с быстрого пути.

По ходу хорошо разобраны мелочи: alignas(64) против false sharing, выбор между compare_exchange_strong и weak, индивидуальный подбор acquire/release/relaxed/seq_cst под каждую операцию, паттерн DEFER в духе Go для парного Protect/Release.

Бенчмарки на 5 млн элементов и 16-ядерном CPU:

🔘2P/2C — 150 мс против 250 мс у мьютекса;
🔘8P/8C — 309 мс против 2152 мс;
🔘16P/16C — 299 мс против 2600 мс;
🔘1P/8C — 254 мс против 3138 мс.

В конце автор замечает: для пары потоков std::mutex остаётся правильным выбором, lock-free нужен там, где много контеншена — рендеринг, HFT, аудио, массовый ingestion.

Полная версия: https://jaysmito.dev/blog/blog/04-fast-lockfree-queues/

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Багу MySQL #11472 — почти 21 год.

Закрыт в этом году.

В июне 2005 года Omer Barnir сообщил: если строки в child-таблице меняются из-за каскадной FK-операции на parent-таблице (ON DELETE CASCADE, ON UPDATE CASCADE, ON DELETE SET NULL), триггеры AFTER DELETE/UPDATE на child-таблице не вызываются. Баг получил severity S2 (Serious). Каждые пару лет в комментариях появлялись новые сообщения от разработчиков: аудит-логи и денормализованные колонки в child-таблицах не отражали реальных изменений после каскада на parent.

Причина архитектурная: каскады обрабатывались внутри InnoDB, а триггеры живут на SQL-уровне сервера. Engine-level каскады просто не могли вызвать триггер. В 2009-м баг переоткрывали в 5.1, в 2010-м обещали починить в форке lp:6.1-fk.

Что починили:

- в MySQL 9.6 ввели SQL-layer foreign key handling, переменная innodb_native_foreign_keys; при OFF каскады выполняются на уровне сервера и можно вызвать триггер;
- в MySQL 9.7 добавили opt-in переменную enable_cascade_triggers; при ON и при отключённых native FK в InnoDB BEFORE/AFTER триггеры на child-таблицах вызываются для DELETE/UPDATE CASCADE и SET NULL;
- цепочка каскада ограничена 30 таблицами на одно выражение, чтобы триггер на child не мог войти в бесконечную рекурсию через parent;
- транзакционная семантика сохранена: ошибка в триггере откатывает всё SQL-выражение.

Включается per session, по умолчанию выключена. Приложения, которые годами рассчитывали на текущее поведение, по умолчанию не ломаются.

Баг-репорт: https://bugs.mysql.com/bug.php?id=11472
Разбор от Oracle: https://blogs.oracle.com/mysql/no-more-silent-foreign-key-cascades-mysql-9-7-lets-child-triggers-speak-up

@prog_stuff
👍1
Как вызвать API из письма без JavaScript — инженер из Redo рассказывает, как они шлют миллионы интерактивных писем (отложить подписку, отменить заказ) без редиректа и скриптов.

Подход — два несвязанных куска:

🔘AMP Email от Google. Работает в Gmail и Yahoo, итого около 25% покрытия. Автор честно расписывает, чем AMP бесит: жёсткая валидация, нет :has, prefers-color-scheme, !important, @keyframes, ::before/::after, баги годами не чинят, одобрение домена занимает пять дней через Google Form с CAPTCHA.
🔘CSS-трюки добивают покрытие до 70%. Прячем <input type="checkbox">, связываем с <label>, а в #cb:checked ~ .card { background-image: url(...); } подсовываем URL своего API. Браузер лениво загружает картинку только после клика — это и есть тихий GET-запрос. Сервер отдаёт прозрачный пиксель и делает нужный side effect.

Подвохи у CSS-фокуса:

🔘ловится только первый клик по кнопке. Обходится цепочкой одинаковых кнопок, которые скрывают предыдущую и показывают следующую;
🔘поведение лениво подгружаемого background-image не специфицировано. Теоретически Apple Mail может однажды начать бот-кликать CSS-урлы, как уже делает с <img>. У Redo на этот случай висит «Interactive Email Doomsday» мониторинг.

В тексте есть рабочий пример карточки «отложить подписку на неделю или месяц» с полным HTML и CSS, копируется и работает в AMP, Apple Mail, Thunderbird и новом Outlook.

Полная статья: https://redo.com/eng-blog/how-to-call-an-api-from-an-email/

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Ваша память ещё работает или нейронки уже и помнят всё за вас?

Чтобы это проверить мы приготовили для вас «Меморину» — игру, которая поможет проверить вашу память.

Всё просто: нужно запомнить и выбрать одинаковые карточки. Если память плохая, то рано или поздно вы всё равно справитесь. А если хорошая, то сможете увидеть ваш потолок скорости.

Ну что, готовы проверить? Тогда переходите по ссылке: https://tprg.ru/cyhK
Unicode 18.0 готовится к релизу 15 сентября 2026 года. Сейчас это beta/draft, но набор новых символов уже заморожен.

Главное: стандарт добавляет 13 047 символов. Всего в Unicode будет 172 848 символов.

Что появится:

🔘 4 новые письменности: Chisoi, Jurchen, Seal и архаические клинописные числа.
🔘 Seal — самое крупное добавление: больше 11 тысяч символов древней китайской «малой печати».
🔘 Эмодзи тоже обновятся: cracking face, жесты большим пальцем влево/вправо, гусеница монарха, pickle, маяк, метеор, ластик и сачок.

Для разработчиков важнее не эмодзи. Unicode 18 меняет правила переноса строк, разбиения текста на графемы, сортировки, security/confusables и variation sequences.

Это может влиять на поиск, username, домены, markdown/rendering, редакторы, шрифты, regex и любые системы, которые режут текст «по символам».

Обычным приложениям можно ждать, пока Unicode 18 доедет через ОС, браузеры, ICU и языковые рантаймы. А если вы делаете редактор, текстовый движок, font tooling, security-проверки идентификаторов или поддержку CJK, beta уже стоит прогнать на тестах.

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
2
Сенсоры maintainability: как не дать ИИ-агентам нарастить техдолг

Подробный гайд про контроль качества кода от генеративных агентов — стоит сохранить, если вы используете Claude, Cursor или Copilot в production. В материале на martinfowler.com Birgitta Böckeler из Thoughtworks показывает, как окружить агента системой ограничений и проверок.

Тесты как регрессионный сенсор, статический анализ и проверки сложности работают как автоматический фильтр, не пропускающий проблемы на человеческое ревью. Без такой системы агенты создают техдолг быстрее, чем ускоряют разработку. С ней вы сохраняете контроль над архитектурой и качеством кода.
11
AI Engineer — не переименованный ML-инженер и не разработчик с доступом к API LLM. Это самостоятельная дисциплина со своим мышлением и метриками

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

ML-инженер живёт в модельном слое: датасеты, обучение, архитектура. AI Engineer берёт готовую модель и превращает её в продукт. Разница сидит не в коде, а в слое ответственности. Цикл сборки, оценки и улучшения не заканчивается никогда, и главная сложность в том, чтобы выбрать правильные метрики качества.

RAG, evals, агенты и продакшен-деплой: навыки, которые встречаются в вакансиях снова и снова. Разбираем, что из этого реально нужно и почему в России эта специальность только набирает обороты.
👍1
Попалась статья, где автор нам напоминает про недооценённый файл в Linux — /proc/<pid>/mem. Через него можно читать и записывать память любого процесса в реальном времени.

Просто cat /proc/self/mem выдаёт ошибку ввода-вывода. Чтобы добраться до данных, нужно сначала сделать lseek на нужное смещение, а потом read или write — либо сразу передать смещение через pread/pwrite. После этого можно вытащить или поменять содержимое памяти.

Зачем это нужно: снять «слепок» памяти зависшего приложения и восстановить данные, обойти антиотладку или просто заглянуть процессу внутрь. Стандартный отладочный интерфейс ptrace умеет то же самое через PTRACE_PEEKDATA и PTRACE_POKEDATA, но работать с ним заметно муторнее.

В 2002 году автор написал на этой механике утилиту memfetch для съёмки памяти процесса, а на выходных обновил её под современные 64-битные системы. Бонусом — история про то, как в Linux 2.2 можно было вызвать mmap на этом файле и подвесить всю систему.

@prog_stuff
2👍1