🚀 В .NET 11 Preview 6 появилась новая возможность из C# 15 — extension indexers.
Теперь индексаторы можно объявлять прямо внутри extension-блоков:
Это позволяет добавлять индексаторы к существующим типам без изменения их исходного кода, так же как сегодня работают extension methods.
Фича уже влита в C# 15 Preview и доступна в .NET 11 Preview 6.🔥
https://github.com/dotnet/csharplang/blob/main/proposals/extension-indexers.md
👉 @KodBlog
Теперь индексаторы можно объявлять прямо внутри extension-блоков:
static class E
{
extension(...)
{
int this[...] { get => ...; set => ...; }
}
}
Это позволяет добавлять индексаторы к существующим типам без изменения их исходного кода, так же как сегодня работают extension methods.
Фича уже влита в C# 15 Preview и доступна в .NET 11 Preview 6.
https://github.com/dotnet/csharplang/blob/main/proposals/extension-indexers.md
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
csharplang/proposals/extension-indexers.md at main · dotnet/csharplang
The official repo for the design of the C# programming language - dotnet/csharplang
👍7👎4🔥1🍾1
Docker-ошибка, которую я вижу почти в каждом junior Dockerfile:
должно быть:
почему это важно?
docker кэширует каждую инструкцию как отдельный слой
исходный код меняется с каждым коммитом
поэтому
если поменять порядок, слой с установкой зависимостей остаётся в кэше даже при изменении кода, потому что он зависит только от
одна перестановка строк. экономит 40+ секунд на каждой пересборке. кэшируй зависимости, а не код.
👉 @KodBlog
COPY . .
RUN npm install
должно быть:
COPY package*.json ./
RUN npm install
COPY . .
почему это важно?
docker кэширует каждую инструкцию как отдельный слой
исходный код меняется с каждым коммитом
поэтому
COPY . . ломает кэш, и всё после него (включая npm install) пересобирается с нуля при каждой сборкеесли поменять порядок, слой с установкой зависимостей остаётся в кэше даже при изменении кода, потому что он зависит только от
package.jsonодна перестановка строк. экономит 40+ секунд на каждой пересборке. кэшируй зависимости, а не код.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤5🍾1
Ваш API тормозит в продакшене.
Вы открываете логи.
Сотни записей.
Что дальше?
Логи полезны, но в распределённом .NET-приложении они обычно показывают лишь отдельные фрагменты картины.
Один запрос может пройти через:
→ API
→ другой сервис
→ PostgreSQL
→ Redis
→ брокер сообщений
Когда что-то работает медленно или падает, важно видеть весь маршрут запроса целиком.
Здесь помогают OpenTelemetry и Grafana.
OpenTelemetry собирает телеметрию приложения:
→ трейсы для отслеживания пути запроса
→ логи с контекстом
→ метрики состояния системы
Grafana позволяет анализировать всё это в одном месте.
В результате можно быстро ответить на вопросы:
• Какой запрос был медленным?
• Где именно он потерял время?
• Какой SQL-запрос вызвал задержку?
• Какие логи относятся к этому конкретному запросу?
Вместо поиска иголки в стоге логов вы получаете полную картину происходящего — от входящего HTTP-запроса до последнего вызова базы данных.
👉 @KodBlog
Вы открываете логи.
Сотни записей.
Что дальше?
Логи полезны, но в распределённом .NET-приложении они обычно показывают лишь отдельные фрагменты картины.
Один запрос может пройти через:
→ API
→ другой сервис
→ PostgreSQL
→ Redis
→ брокер сообщений
Когда что-то работает медленно или падает, важно видеть весь маршрут запроса целиком.
Здесь помогают OpenTelemetry и Grafana.
OpenTelemetry собирает телеметрию приложения:
→ трейсы для отслеживания пути запроса
→ логи с контекстом
→ метрики состояния системы
Grafana позволяет анализировать всё это в одном месте.
В результате можно быстро ответить на вопросы:
• Какой запрос был медленным?
• Где именно он потерял время?
• Какой SQL-запрос вызвал задержку?
• Какие логи относятся к этому конкретному запросу?
Вместо поиска иголки в стоге логов вы получаете полную картину происходящего — от входящего HTTP-запроса до последнего вызова базы данных.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4🥴1🍾1
Большинству разработчиков в 2026 году уже не обязательно платить за AI-инструменты.
Бесплатные тарифы стали настолько щедрыми, что ими можно закрыть почти весь рабочий процесс.
Мой стек за $0:
→ Rider — бесплатно для некоммерческого использования
→ Cursor Hobby — AI прямо в редакторе
→ NotebookLM — работа с документацией и RFC через RAG
→ Granola — конспекты встреч и action items
→ Grammarly — исправление английского на лету
→ Gamma — генерация презентаций за минуты
→ Excalidraw — архитектурные диаграммы без боли
Код, документация, встречи, презентации, диаграммы и AI-помощники.
Ещё пару лет назад такой набор обходился бы в сотни долларов в год. Теперь большая часть доступна бесплатно.
👉 @KodBlog
Бесплатные тарифы стали настолько щедрыми, что ими можно закрыть почти весь рабочий процесс.
Мой стек за $0:
→ Rider — бесплатно для некоммерческого использования
→ Cursor Hobby — AI прямо в редакторе
→ NotebookLM — работа с документацией и RFC через RAG
→ Granola — конспекты встреч и action items
→ Grammarly — исправление английского на лету
→ Gamma — генерация презентаций за минуты
→ Excalidraw — архитектурные диаграммы без боли
Код, документация, встречи, презентации, диаграммы и AI-помощники.
Ещё пару лет назад такой набор обходился бы в сотни долларов в год. Теперь большая часть доступна бесплатно.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9🍾2
Собрать 500 файлов без единой ошибки и всё равно не получить исполняемый файл. Звучит странно, но это чистая правда.
Когда один модуль вызывает функцию, которая ссылается на функции, переменные или структуры из другого модуля, компилятор ничего не разрешает. Он просто оставляет пометку. В объектном файле появляется запись о внешнем символе, и компилятору этого достаточно.
Дальше в дело вступает компоновщик, или линкер. Он собирает все объектные файлы, разрешает ссылки между модулями, назначает финальные адреса и выполняет перемещение кода. Без него каждый файл компилируется по отдельности, но ни один из них не становится частью программы.
Собирать по кирпичикам, а не лепить кое-как. Есть статические линкеры и динамические, но об этом в другой раз.
👉 @KodBlog
Когда один модуль вызывает функцию, которая ссылается на функции, переменные или структуры из другого модуля, компилятор ничего не разрешает. Он просто оставляет пометку. В объектном файле появляется запись о внешнем символе, и компилятору этого достаточно.
Дальше в дело вступает компоновщик, или линкер. Он собирает все объектные файлы, разрешает ссылки между модулями, назначает финальные адреса и выполняет перемещение кода. Без него каждый файл компилируется по отдельности, но ни один из них не становится частью программы.
Собирать по кирпичикам, а не лепить кое-как. Есть статические линкеры и динамические, но об этом в другой раз.
Please open Telegram to view this post
VIEW IN TELEGRAM
🥴4❤2😐1🍾1
Что нового в PostgreSQL 19?
PostgreSQL 19 продолжает одну важную тенденцию. Postgres превращается во что-то гораздо большее, чем просто реляционная база.
Самые интересные новинки:
Графовые запросы через SQL/PGQ
PostgreSQL 19 научился выполнять SQL Property Graph Queries. Теперь можно запрашивать связи прямо на SQL, без отдельной графовой базы. Пригодится для соцсетей, рекомендаций, поиска мошенничества и графов зависимостей.
GROUP BY ALL
Вместо того чтобы перечислять все колонки в GROUP BY, пишешь GROUP BY ALL. Postgres сам группирует по неагрегатным колонкам. Меньше шаблонного кода, меньше ошибок.
WAIT FOR LSN
Фича для приложений, которые используют реплики чтения. Позволяет подождать, пока реплика догонит основную базу, прежде чем читать данные. Полезно для консистентности «прочитал то, что написал».
Лучшая поддержка JSON
Postgres и дальше улучшает работу с полуструктурированными данными, не теряя при этом SQL, индексы, соединения и транзакции.
PostgreSQL 19 пока в бете. Детали могут поменяться к релизу. Но направление понятно. Postgres потихоньку становится одной платформой под всё: реляционные данные, документы, графы, аналитика и векторы для AI.
👉 @KodBlog
PostgreSQL 19 продолжает одну важную тенденцию. Postgres превращается во что-то гораздо большее, чем просто реляционная база.
Самые интересные новинки:
Графовые запросы через SQL/PGQ
PostgreSQL 19 научился выполнять SQL Property Graph Queries. Теперь можно запрашивать связи прямо на SQL, без отдельной графовой базы. Пригодится для соцсетей, рекомендаций, поиска мошенничества и графов зависимостей.
GROUP BY ALL
Вместо того чтобы перечислять все колонки в GROUP BY, пишешь GROUP BY ALL. Postgres сам группирует по неагрегатным колонкам. Меньше шаблонного кода, меньше ошибок.
WAIT FOR LSN
Фича для приложений, которые используют реплики чтения. Позволяет подождать, пока реплика догонит основную базу, прежде чем читать данные. Полезно для консистентности «прочитал то, что написал».
Лучшая поддержка JSON
Postgres и дальше улучшает работу с полуструктурированными данными, не теряя при этом SQL, индексы, соединения и транзакции.
PostgreSQL 19 пока в бете. Детали могут поменяться к релизу. Но направление понятно. Postgres потихоньку становится одной платформой под всё: реляционные данные, документы, графы, аналитика и векторы для AI.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🍾1
Мой племянник учится на втором курсе программной инженерии. Позвонил недавно, попросил помочь с поиском стажировки. И среди прочего спросил, где лучше разобраться с Git. Я удивился. На втором курсе студенты всё ещё обходят Git стороной. А потом это бьёт по ним на собеседованиях.
Я посоветовал ему отличный гайд от Beej.
Он перезвонил сегодня. Полный восторга. Делился впечатлениями. Так что вот, снова рекомендую. Для всех студентов и всех, кто только начинает знакомство с Git.
https://beej.us/guide/bggit/
👉 @KodBlog
Я посоветовал ему отличный гайд от Beej.
Он перезвонил сегодня. Полный восторга. Делился впечатлениями. Так что вот, снова рекомендую. Для всех студентов и всех, кто только начинает знакомство с Git.
https://beej.us/guide/bggit/
Please open Telegram to view this post
VIEW IN TELEGRAM
🍾4❤3
20 законов разработки, которые должен знать каждый инженер
1. Закон Галла: Работающая сложная система вырастает из работающей простой.
2. KISS: Делай проще. Всё остальное — оверхеад.
3. Закон Конвея: Компании проектируют системы, которые повторяют структуру их коммуникаций.
4. Закон Хайрума: У достаточно большого API уже неважно, что ты обещал в контракте. Кто-нибудь уже зависит от каждого observable-поведения твоей системы.
5. CAP-теорема: Выбери два: консистентность, доступность, устойчивость к разделению.
6. Закон Завински: Любая программа разрастается до тех пор, пока не научится читать почту.
7. Закон Брукса: Добавление людей в опаздывающий проект делает его ещё более поздним.
8. Эффект Рингельмана: Производительность каждого участника группы падает с ростом группы.
9. Закон Прайса: Половину работы делают квадратный корень от всех людей.
10. Эффект Даннинга — Крюгера: Новички переоценивают свои способности, эксперты — недооценивают.
11. Закон Хофштадтера: Всё занимает больше времени, чем ты планируешь, даже с учётом этого закона.
12. Закон Паркинсона: Работа расширяется, чтобы заполнить всё отведённое на неё время.
13. Закон Гудхарта: Когда метрика становится целью, она перестаёт быть хорошей метрикой.
14. Закон Гилба: Измерять неточно лучше, чем не измерять вообще.
15. Принцип Кнута: Забудь о микрооптимизациях в 97% случаев. Преждевременная оптимизация — корень всех зол.
16. Закон Амдала: Ускорение одной части системы ограничено долей времени, которое эта часть реально используется.
17. Закон Мёрфи: Если что-то может пойти не так, оно пойдёт не так.
18. Закон Постела: Будь консервативен в том, что отправляешь, и либерален в том, что принимаешь.
19. Закон Стерджена: 90% всего на свете — фигня.
20. Закон Каннингема: Лучший способ получить правильный ответ в интернете — не задать вопрос, а написать неправильный ответ.
👉 @KodBlog
1. Закон Галла: Работающая сложная система вырастает из работающей простой.
2. KISS: Делай проще. Всё остальное — оверхеад.
3. Закон Конвея: Компании проектируют системы, которые повторяют структуру их коммуникаций.
4. Закон Хайрума: У достаточно большого API уже неважно, что ты обещал в контракте. Кто-нибудь уже зависит от каждого observable-поведения твоей системы.
5. CAP-теорема: Выбери два: консистентность, доступность, устойчивость к разделению.
6. Закон Завински: Любая программа разрастается до тех пор, пока не научится читать почту.
7. Закон Брукса: Добавление людей в опаздывающий проект делает его ещё более поздним.
8. Эффект Рингельмана: Производительность каждого участника группы падает с ростом группы.
9. Закон Прайса: Половину работы делают квадратный корень от всех людей.
10. Эффект Даннинга — Крюгера: Новички переоценивают свои способности, эксперты — недооценивают.
11. Закон Хофштадтера: Всё занимает больше времени, чем ты планируешь, даже с учётом этого закона.
12. Закон Паркинсона: Работа расширяется, чтобы заполнить всё отведённое на неё время.
13. Закон Гудхарта: Когда метрика становится целью, она перестаёт быть хорошей метрикой.
14. Закон Гилба: Измерять неточно лучше, чем не измерять вообще.
15. Принцип Кнута: Забудь о микрооптимизациях в 97% случаев. Преждевременная оптимизация — корень всех зол.
16. Закон Амдала: Ускорение одной части системы ограничено долей времени, которое эта часть реально используется.
17. Закон Мёрфи: Если что-то может пойти не так, оно пойдёт не так.
18. Закон Постела: Будь консервативен в том, что отправляешь, и либерален в том, что принимаешь.
19. Закон Стерджена: 90% всего на свете — фигня.
20. Закон Каннингема: Лучший способ получить правильный ответ в интернете — не задать вопрос, а написать неправильный ответ.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17❤3😁2🍾2🔥1
Раз Postgres 19 получает FOR PORTION OF для темпоральных таблиц, давай поговорим про BRIN-индексы. Они отлично подходят для больших append-only таблиц с коррелированными колонками вроде таймстемпов. Маленькие, быстро создаются, хорошо работают на range-запросах.
Как работают? Бакетируют значения. B-tree индекс на колонке с таймстемпами на 5 миллионов строк — ~107 MB. BRIN на той же колонке — ~48 kB. Есть нюансы, но иногда овчинка стоит выделки.
Block Range INdex
BRIN не хранит запись на каждую строку. Вместо этого он делит heap на диапазоны по 128 страниц и хранит только min и max значение индексируемой колонки для каждого диапазона.
Для
- если диапазон не пересекается с фильтром — пропускает весь диапазон (128 страниц × 8kB = 1MB скипа за раз)
- если пересекается — читает эти страницы и проверяет строки
Нужна физическая корреляция
BRIN работает только когда строки хранятся примерно в том же порядке, в котором вставляются. Если таблица append-only и строки вставляются по порядку таймстемпов, каждая страница heap содержит строки из непрерывного временного отрезка. BRIN может пропускать большие куски таблицы.
Если таймстемпы случайные (бэкфилл исторических данных, перемешанные вставки), BRIN ничего не пропускает и вырождается в полный скан таблицы.
Append-only таблицы событий, логов и time-series данных обычно имеют корреляцию около 1.0. Запрос из вложения помогает понять, подойдёт ли BRIN для колонки.
autosummarize
BRIN можно создать с опцией
Настройка pages_per_range
При создании BRIN-индекса можно указать
👉 @KodBlog
Как работают? Бакетируют значения. B-tree индекс на колонке с таймстемпами на 5 миллионов строк — ~107 MB. BRIN на той же колонке — ~48 kB. Есть нюансы, но иногда овчинка стоит выделки.
Block Range INdex
BRIN не хранит запись на каждую строку. Вместо этого он делит heap на диапазоны по 128 страниц и хранит только min и max значение индексируемой колонки для каждого диапазона.
Для
WHERE created_at BETWEEN '2026-06-01' AND '2026-07-01' Postgres проверяет каждый диапазон:- если диапазон не пересекается с фильтром — пропускает весь диапазон (128 страниц × 8kB = 1MB скипа за раз)
- если пересекается — читает эти страницы и проверяет строки
Нужна физическая корреляция
BRIN работает только когда строки хранятся примерно в том же порядке, в котором вставляются. Если таблица append-only и строки вставляются по порядку таймстемпов, каждая страница heap содержит строки из непрерывного временного отрезка. BRIN может пропускать большие куски таблицы.
Если таймстемпы случайные (бэкфилл исторических данных, перемешанные вставки), BRIN ничего не пропускает и вырождается в полный скан таблицы.
Append-only таблицы событий, логов и time-series данных обычно имеют корреляцию около 1.0. Запрос из вложения помогает понять, подойдёт ли BRIN для колонки.
autosummarize
BRIN можно создать с опцией
autosummarize (по умолчанию выключена). Тогда вставки автоматически обновляют min/max для каждого диапазона. Без этой опции новые строки не попадают в индекс до REINDEX или VACUUM. Когда отключать? Если последние строки не запрашиваются и можно подождать autovacuum.Настройка pages_per_range
При создании BRIN-индекса можно указать
pages_per_range. По умолчанию 128 — каждый entry покрывает 1 MB heap. Меньшие значения делают индекс точнее за счёт большего числа записей. Для большинства append-only таблиц 128 — хороший старт.Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🍾2
Postgres использует эффективный по кешу и CPU алгоритм, когда за
Логично, правда? Если бы вас попросили взять 10 самых больших камней из кучи в 100 камней, вы бы не выстраивали все камни от маленького к большому, а потом брали 10 самых больших. Вы бы отложили 10 в порядке, а затем сравнивали каждый камень с самым маленьким из этих 10 и заменяли бы его, если новый камень больше. (У вас есть возможности, которых нет у баз данных: «быстрый визуальный поиск больших объектов», операторы вроде «визуальная оценка размера» и «взять камень и сравнить ощущаемый вес».)
Это top-N heapsort (пирамидальная сортировка top-N).
При выполнении
Всего 25кБ памяти? Это та маленькая кучка камней, которую вы держите в памяти, пока сканируете всю таблицу.
Без
Используемая память =
А что насчёт _неразумного_ лимита?
Видели когда-нибудь URL пагинации с
Когда лимит становится слишком большим, Postgres в конечном счёте переключается на quicksort или внешнюю сортировку слиянием (а это убийственно).
Postgres принимает решение на этапе планирования, основываясь на соотношении оценочного количества входных строк к N. Когда N приближается к числу сортируемых строк, поддержание кучи перестаёт быть выгодным, и вступает quicksort. Точная точка перехода зависит от размера строки и оценки планировщика. Ниже приведён гипотетический пример переключения планировщика с top-N heapsort на quicksort. Использование памяти — это объём памяти, занятый сортировкой, а не общее потребление памяти запросом.
Не забывайте про индексы
Top-N heapsort — это оптимизация сортировки неиндексированного набора данных. Она всё равно требует полного последовательного сканирования входных данных. Для 10 самых последних событий среди 1M строк она каждый раз сканирует все 1M строк. Индекс по
👉 @KodBlog
ORDER BY следует _разумный_ LIMIT. С LIMIT алгоритм сортировки может использовать всего 25кБ памяти. Без LIMIT алгоритму сортировки требуется хранить весь результирующий набор в кеше.Логично, правда? Если бы вас попросили взять 10 самых больших камней из кучи в 100 камней, вы бы не выстраивали все камни от маленького к большому, а потом брали 10 самых больших. Вы бы отложили 10 в порядке, а затем сравнивали каждый камень с самым маленьким из этих 10 и заменяли бы его, если новый камень больше. (У вас есть возможности, которых нет у баз данных: «быстрый визуальный поиск больших объектов», операторы вроде «визуальная оценка размера» и «взять камень и сравнить ощущаемый вес».)
Это top-N heapsort (пирамидальная сортировка top-N).
При выполнении
EXPLAIN ANALYZE на запросе ниже приведён пример top-N heapsort:Sort (cost=...) (actual time=... rows=10 loops=1)
Sort Key: created_at DESC
Sort Method: top-N heapsort Memory: 25kB
-> Seq Scan on events (rows=1000000 ...)
Всего 25кБ памяти? Это та маленькая кучка камней, которую вы держите в памяти, пока сканируете всю таблицу.
Без
LIMIT используется quicksort (быстрая сортировка), которой нужно держать в памяти весь входной набор, отсортировать его, а затем вернуть первые N строк. Top-N heapsort поддерживает min-кучу фиксированного размера ровно из N кортежей и прогоняет через неё поток входных данных. Вычислительная сложность — O(M log N), где M — количество просканированных строк, а N — LIMIT. По сравнению с O(M log M) для полной сортировки, top-N heapsort также быстрее для CPU.Используемая память =
N × row_size (где N — LIMIT). Для LIMIT 10 со строками по 20 байт это 200 байт. Postgres округляет до минимума в 25кБ для выравнивания и служебных данных. В любом случае, для _разумного_ LIMIT сброса на диск не произойдёт независимо от размера таблицы.А что насчёт _неразумного_ лимита?
Видели когда-нибудь URL пагинации с
per_page=10? Что произойдёт, если изменить его на per_page=1000000, а приложение не валидирует ввод, и запрос получает LIMIT 1000000?Когда лимит становится слишком большим, Postgres в конечном счёте переключается на quicksort или внешнюю сортировку слиянием (а это убийственно).
Postgres принимает решение на этапе планирования, основываясь на соотношении оценочного количества входных строк к N. Когда N приближается к числу сортируемых строк, поддержание кучи перестаёт быть выгодным, и вступает quicksort. Точная точка перехода зависит от размера строки и оценки планировщика. Ниже приведён гипотетический пример переключения планировщика с top-N heapsort на quicksort. Использование памяти — это объём памяти, занятый сортировкой, а не общее потребление памяти запросом.
LIMIT 10: Sort Method: top-N heapsort Memory: 25kB
LIMIT 100: Sort Method: top-N heapsort Memory: 30kB
LIMIT 1,000: Sort Method: top-N heapsort Memory: 97kB
LIMIT 10,000: Sort Method: top-N heapsort Memory: 914kB
LIMIT 100,000: Sort Method: quicksort Memory: 9,113kB
Не забывайте про индексы
Top-N heapsort — это оптимизация сортировки неиндексированного набора данных. Она всё равно требует полного последовательного сканирования входных данных. Для 10 самых последних событий среди 1M строк она каждый раз сканирует все 1M строк. Индекс по
(created_at DESC) извлёк бы эти 10 строк напрямую, без сканирования всего набора данных.Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🍾1
Вот лучший способ версионировать API.
Но никто его не использует.
Слышали про версионирование через media type?
Это самый чистый подход к версионированию API.
1. Вы указываете версию API в заголовке Accept.
2. Сервер направляет запросы к соответствующему эндпоинту.
Вы не засоряете URL версиями. Это также можно расширить с помощью контент-nego.
Но версионирование API — лишь средство для достижения цели. Лучший API вообще не использует версионирование.
Вместо этого вам нужен change management.
Change management означает развитие API без неожиданностей и поломок для существующих клиентов. Вместо того чтобы сразу создавать v2, вы сначала спрашиваете: можно ли сделать изменение аддитивным, могут ли старая и новая функциональность сосуществовать, безопаснее ли новая операция, чем изменение существующей, и можно ли обработать deprecation через документацию, runtime-сигналы, миграционные гайды и телеметрию.
👉 @KodBlog
Но никто его не использует.
Слышали про версионирование через media type?
Это самый чистый подход к версионированию API.
1. Вы указываете версию API в заголовке Accept.
2. Сервер направляет запросы к соответствующему эндпоинту.
Вы не засоряете URL версиями. Это также можно расширить с помощью контент-nego.
Но версионирование API — лишь средство для достижения цели. Лучший API вообще не использует версионирование.
Вместо этого вам нужен change management.
Change management означает развитие API без неожиданностей и поломок для существующих клиентов. Вместо того чтобы сразу создавать v2, вы сначала спрашиваете: можно ли сделать изменение аддитивным, могут ли старая и новая функциональность сосуществовать, безопаснее ли новая операция, чем изменение существующей, и можно ли обработать deprecation через документацию, runtime-сигналы, миграционные гайды и телеметрию.
Please open Telegram to view this post
VIEW IN TELEGRAM
🍾4❤1
Исторический момент. Новый HTTP-метод в стандарте.
QUERY. Альтернатива GET и POST.
Как GET — не меняет состояние ресурса. Как POST — можно использовать тело запроса. Шлёшь JSON, кешируешь ответ.
Только что повышен до Proposed Standard.
👉 @KodBlog
QUERY. Альтернатива GET и POST.
Как GET — не меняет состояние ресурса. Как POST — можно использовать тело запроса. Шлёшь JSON, кешируешь ответ.
Только что повышен до Proposed Standard.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍24🤔3🍾1
This media is not supported in your browser
VIEW IN TELEGRAM
ОДИН РАЗРАБОТЧИК ЗАНОВО ПРИДУМАЛ ФОРМАТ PDF. И проблема, которую он решил, до смешного очевидна.
Банк попросил его предоставить 17 PDF-файлов для оформления ипотеки.
Он открывал их по одному.
Закрывал их по одному.
Объединял их в один файл.
Стало только хуже.
Тогда он подумал: а что, если PDF работал бы как Figma?
Горизонтальная прокрутка — между страницами.
Вертикальная — между файлами.
До него этого никто не сделал.
Поэтому он расширил стандарт PDF, добавив метаданные.
Он придумал новый формат.
Назвал его .pdfx.
Claude сделал 80% проекта за 2 часа.
В этом и разница между тем, чтобы десятилетиями жаловаться на нерешённую проблему… и однажды настолько устать от неё, что взять и исправить всё самому.
https://github.com/AlexandrosGounis/pdfx
👉 @KodBlog
Банк попросил его предоставить 17 PDF-файлов для оформления ипотеки.
Он открывал их по одному.
Закрывал их по одному.
Объединял их в один файл.
Стало только хуже.
Тогда он подумал: а что, если PDF работал бы как Figma?
Горизонтальная прокрутка — между страницами.
Вертикальная — между файлами.
До него этого никто не сделал.
Поэтому он расширил стандарт PDF, добавив метаданные.
Он придумал новый формат.
Назвал его .pdfx.
Claude сделал 80% проекта за 2 часа.
В этом и разница между тем, чтобы десятилетиями жаловаться на нерешённую проблему… и однажды настолько устать от неё, что взять и исправить всё самому.
https://github.com/AlexandrosGounis/pdfx
Please open Telegram to view this post
VIEW IN TELEGRAM
❤16🔥6🍾2🥰1
Короткий конспект по классическим паттернам проектирования.
Внутри:
→ Factory — создание объектов через единый интерфейс
→ Builder — пошаговая сборка сложных объектов
→ Prototype — клонирование объектов вместо создания с нуля
→ Singleton — один экземпляр на всё приложение
→ Chain of Responsibility — цепочка обработчиков запросов
Подходит как быстрый референс без погружения в теорию.
👉 @KodBlog
Внутри:
→ Factory — создание объектов через единый интерфейс
→ Builder — пошаговая сборка сложных объектов
→ Prototype — клонирование объектов вместо создания с нуля
→ Singleton — один экземпляр на всё приложение
→ Chain of Responsibility — цепочка обработчиков запросов
Подходит как быстрый референс без погружения в теорию.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🍾1
Сможешь решить типичную задачу с собеседований?
Нужно понимать, как работают бинарные деревья.
Я давно с деревьями не работал — со времён университета.
Поэтому на разбор ушло несколько минут.
Вспомнил, что для обхода в ширину (Breadth-first traversal) нужна очередь, с этого и начал.
На выходе получилось:
Значит, узлы обрабатывались в правильном порядке.
Следующий вопрос — когда печатать перевод строки.
Решил отслеживать уровень каждого узла в дереве. По мере обхода увеличивал текущий уровень.
В целом — нормальное упражнение.
В универе я бы такое сделал не задумываясь.
Это вообще имеет отношение к работе?
Может и да, но люди часто не понимают смысл.
Тут проверяют умение решать задачи.
Можешь придумать другое решение?
P.S. Постарайся не использовать ИИ для этого… ради всего, что связано с разработкой.
👉 @KodBlog
Нужно понимать, как работают бинарные деревья.
Я давно с деревьями не работал — со времён университета.
Поэтому на разбор ушло несколько минут.
Вспомнил, что для обхода в ширину (Breadth-first traversal) нужна очередь, с этого и начал.
На выходе получилось:
1 2 3 4 5 6.Значит, узлы обрабатывались в правильном порядке.
Следующий вопрос — когда печатать перевод строки.
Решил отслеживать уровень каждого узла в дереве. По мере обхода увеличивал текущий уровень.
В целом — нормальное упражнение.
В универе я бы такое сделал не задумываясь.
Это вообще имеет отношение к работе?
Может и да, но люди часто не понимают смысл.
Тут проверяют умение решать задачи.
Можешь придумать другое решение?
P.S. Постарайся не использовать ИИ для этого… ради всего, что связано с разработкой.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🍾1
Интересный новый бенчмарк проекции языков WinRT: Rust самый быстрый, C++ недалеко позади, C# пока догоняет. Внутренний push на C# для ОС и приложений не оставляет ли слишком много производительности на столе? 🤔
https://github.com/microsoft/windows-rs/blob/master/crates%2Fsamples%2Flang_perf%2Freadme.md
(время в мс; меньше — лучше)
На фото 2 обновлено под .NET 10.
👉 @KodBlog
https://github.com/microsoft/windows-rs/blob/master/crates%2Fsamples%2Flang_perf%2Freadme.md
(время в мс; меньше — лучше)
На фото 2 обновлено под .NET 10.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
2🍾1
Прежде чем код можно будет переиспользовать, он должен быть пригоден к использованию.
Большинство разработчиков строят абстракции для кода, который живёт ровно в одном месте.
Один интерфейс. Одна реализация. Один вызывающий. Навсегда.
И называют это «чистым кодом».
Вот в чём ловушка →
Абстракция, построенная для переиспользования, которое никогда не наступает — не переиспользуема. Это просто лишний слой, который надо прочитать, чтобы понять, что код на самом деле делает.
📌 Сначала удобство использования. Переиспользование — то, что вы зарабатываете потом.
Самая частая пустая трата, которую я вижу:
- ❌
- ✅ Конкретный класс, который можно прочитать от начала до конца
- ❌ Общая база «для будущей гибкости», которая никогда не гнётся
- ✅ Простая прямая версия, решающая сегодняшнюю задачу
- ❌ Фабрика, оборачивающая создание одного объекта
- ✅ Внедрение объекта напрямую через DI
Каждая лишняя абстракция усложняет использование кода.
Больше файлов для открытия. Больше косвенности для трассировки. Больше догадок, зачем это существует.
👉 Честный тест перед тем, как выносить абстракцию:
1. Есть ли у меня второй или третий реальный вызывающий код прямо сейчас? (Не «может быть потом»)
2. Это делает код проще в использовании или просто даёт повод гордиться собой?
3. Сможет ли следующий разработчик разобраться в этом без моих объяснений?
Если ответ «нет» — удаляйте слой. Пишите конкретную реализацию.
Вы не теряете переиспользование.
Вы сохраняете код удобным до тех пор, пока переиспользование действительно не появится.
А когда оно появится — правильная абстракция станет очевидной, потому что у вас наконец будет два или три реальных примера, чтобы её сформировать.
Преждевременная абстракция — это сложность, за которую вы платите сегодня ради выгоды, которая может никогда не наступить.
Сделайте код удобным сначала. Абстрагируйте только тогда, когда второй реальный сценарий использования вынудит вас это сделать.
👉 @KodBlog
Большинство разработчиков строят абстракции для кода, который живёт ровно в одном месте.
Один интерфейс. Одна реализация. Один вызывающий. Навсегда.
И называют это «чистым кодом».
Вот в чём ловушка →
Абстракция, построенная для переиспользования, которое никогда не наступает — не переиспользуема. Это просто лишний слой, который надо прочитать, чтобы понять, что код на самом деле делает.
📌 Сначала удобство использования. Переиспользование — то, что вы зарабатываете потом.
Самая частая пустая трата, которую я вижу:
- ❌
IThingService с одной реализацией «на всякий случай»- ✅ Конкретный класс, который можно прочитать от начала до конца
- ❌ Общая база «для будущей гибкости», которая никогда не гнётся
- ✅ Простая прямая версия, решающая сегодняшнюю задачу
- ❌ Фабрика, оборачивающая создание одного объекта
- ✅ Внедрение объекта напрямую через DI
Каждая лишняя абстракция усложняет использование кода.
Больше файлов для открытия. Больше косвенности для трассировки. Больше догадок, зачем это существует.
👉 Честный тест перед тем, как выносить абстракцию:
1. Есть ли у меня второй или третий реальный вызывающий код прямо сейчас? (Не «может быть потом»)
2. Это делает код проще в использовании или просто даёт повод гордиться собой?
3. Сможет ли следующий разработчик разобраться в этом без моих объяснений?
Если ответ «нет» — удаляйте слой. Пишите конкретную реализацию.
Вы не теряете переиспользование.
Вы сохраняете код удобным до тех пор, пока переиспользование действительно не появится.
А когда оно появится — правильная абстракция станет очевидной, потому что у вас наконец будет два или три реальных примера, чтобы её сформировать.
Преждевременная абстракция — это сложность, за которую вы платите сегодня ради выгоды, которая может никогда не наступить.
Сделайте код удобным сначала. Абстрагируйте только тогда, когда второй реальный сценарий использования вынудит вас это сделать.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6👍4🍾3
Если хочешь стать по-настоящему сильным в .NET,
изучи следующие концепции:
1. CLR и JIT-компиляция
2. Сборка мусора (Garbage Collection)
3. Поколения памяти (Gen 0/1/2 и LOH)
4. Типы значений (Value Types) и ссылочные типы (Reference Types)
5. Boxing и Unboxing
6. Стек и куча (Stack vs Heap)
7. Span<T> и Memory<T>
8. ref struct и stackalloc
9. IDisposable и using
10. Финализаторы (Finalizers)
11. Async/Await
12. Task и ValueTask
13. SynchronizationContext
14. ConfigureAwait
15. CancellationToken
16. IAsyncEnumerable
17. Потоки и пул потоков (Threading & Thread Pool)
18. lock, Monitor и Semaphore
19. Channels
20. Parallel и PLINQ
21. LINQ и отложенное выполнение (Deferred Execution)
22. IEnumerable и IQueryable
23. Делегаты и события (Delegates & Events)
24. Func, Action и Predicate
25. Деревья выражений (Expression Trees)
26. Дженерики и ограничения (Generics & Constraints)
27. Ковариантность и контравариантность
28. Records и сопоставление с образцом (Pattern Matching)
29. Nullable Reference Types
30. Внедрение зависимостей (Dependency Injection)
31. Жизненные циклы сервисов (Scoped/Singleton/Transient)
32. Конвейер middleware (Middleware Pipeline)
33. Minimal APIs и Controllers
34. Привязка моделей и валидация (Model Binding & Validation)
35. Конфигурация и паттерн Options
36. IHostedService и BackgroundService
37. Entity Framework Core
38. Отслеживание изменений (Change Tracking)
39. Миграции (Migrations)
40. Проблема N+1
41. Пул подключений (Connection Pooling)
42. Dapper и Raw SQL
43. Кэширование (IMemoryCache и Distributed Cache)
44. Output Caching
45. Генераторы исходного кода (Source Generators)
46. Рефлексия и атрибуты (Reflection & Attributes)
47. AssemblyLoadContext
48. Native AOT
49. Бенчмаркинг (BenchmarkDotNet)
50. Профилирование памяти и настройка GC (Memory Profiling & GC Tuning)
👉 @KodBlog
изучи следующие концепции:
1. CLR и JIT-компиляция
2. Сборка мусора (Garbage Collection)
3. Поколения памяти (Gen 0/1/2 и LOH)
4. Типы значений (Value Types) и ссылочные типы (Reference Types)
5. Boxing и Unboxing
6. Стек и куча (Stack vs Heap)
7. Span<T> и Memory<T>
8. ref struct и stackalloc
9. IDisposable и using
10. Финализаторы (Finalizers)
11. Async/Await
12. Task и ValueTask
13. SynchronizationContext
14. ConfigureAwait
15. CancellationToken
16. IAsyncEnumerable
17. Потоки и пул потоков (Threading & Thread Pool)
18. lock, Monitor и Semaphore
19. Channels
20. Parallel и PLINQ
21. LINQ и отложенное выполнение (Deferred Execution)
22. IEnumerable и IQueryable
23. Делегаты и события (Delegates & Events)
24. Func, Action и Predicate
25. Деревья выражений (Expression Trees)
26. Дженерики и ограничения (Generics & Constraints)
27. Ковариантность и контравариантность
28. Records и сопоставление с образцом (Pattern Matching)
29. Nullable Reference Types
30. Внедрение зависимостей (Dependency Injection)
31. Жизненные циклы сервисов (Scoped/Singleton/Transient)
32. Конвейер middleware (Middleware Pipeline)
33. Minimal APIs и Controllers
34. Привязка моделей и валидация (Model Binding & Validation)
35. Конфигурация и паттерн Options
36. IHostedService и BackgroundService
37. Entity Framework Core
38. Отслеживание изменений (Change Tracking)
39. Миграции (Migrations)
40. Проблема N+1
41. Пул подключений (Connection Pooling)
42. Dapper и Raw SQL
43. Кэширование (IMemoryCache и Distributed Cache)
44. Output Caching
45. Генераторы исходного кода (Source Generators)
46. Рефлексия и атрибуты (Reflection & Attributes)
47. AssemblyLoadContext
48. Native AOT
49. Бенчмаркинг (BenchmarkDotNet)
50. Профилирование памяти и настройка GC (Memory Profiling & GC Tuning)
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7❤4🍾1