23284
Все самое полезное для C#-разработчика в одном канале. По рекламе: @proglib_adv Учиться у нас: https://proglib.io/w/b60af5a4 Для обратной связи: @proglibrary_feeedback_bot РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead
👨💻 Паттерны проектирования — не для облачных систем
Классические design patterns из Банды четырёх часто вредят cloud-native приложениям.
Большинство классических паттернов проектирования создавались для in-process объектно-ориентированных систем — а не для распределённых, подверженных сбоям облачных окружений.
Но в 2026 году всё ещё встречаются облачные системы, построенные на репозиториях повсюду, синглтонах как кеше и фасаде, оборачивающем HTTP-вызовы.
Классические паттерны из книги Банды Четырёх предполагают общую память, быстрые вызовы методов, стабильные процессы, редкие сбои и единый блок развёртывания. Облачные системы предполагают противоположное: распределённую память, сетевые вызовы с задержками, временные процессы, постоянные частичные сбои и множество независимых сервисов.
Синглтон: самый опасный паттерн
Синглтон кажется удобным для глобального состояния в одном процессе. В облаке каждый под имеет свой экземпляр, и состояние рассинхронизируется при масштабировании. Холодные старты сбрасывают данные, а поды работают с разными версиями.
Репозиторий тормозит запросы
Репозиторий абстрагирует данные, чтобы домен оставался чистым. В распределённых системах это плодит лишние вызовы через сеть, N+1 проблемы и перерасход ресурсов БД. Каждый запрос добавляет задержку и траты.
Лучше ориентироваться на запросы: оптимизировать чтение, использовать CQRS для доминирующего чтения и принимать форму данных как часть дизайна. Доступ к БД становится ключевой частью архитектуры, а не скрытой деталью.
Фабрика усложняет жизнь
Фабрики прячут создание объектов и типы. В облаке они дублируют DI-контейнеры, маскируют жизненный цикл и ломают трассировку. Если код полон фабрик, локаторов и инъекций, ясность теряется.
Платформы вроде Kubernetes берут управление lifecycle на себя. Делайте ресурсы явными, отдавайте композицию контейнерам и избегайте лишних прослоек.
Обдумывайте контекст перед копипастой паттернов. Это спасёт от боли при росте нагрузки.
💬 Был у вас шаблон, который подставил вас в облаке?
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#sharp_view
Завтра стартуем: курс по разработке ИИ-агентов в .NET 💠
Хватит писать бойлерплейт — переходите к архитектуре автономных систем. Мы научим проектировать мультиагентные связки на CrewAI, управлять стейтом в LangGraph и подключать нейросети к вашим API и облаку.
👉 Успейте занять место до начала занятий
Задачи копятся, а ты всё ещё вручную «жаришь» контроллеры под каждый промпт?
Это работа в забегаловке. Настоящий Шеф не пишет услуги вечно — он проектирует Систему. 💠
В понедельник, 26 января, стартует интенсив по разработке ИИ-агентов. Мы научим создавать автономные решения в экосистеме .NET, которые закроют рутину, пока ты занимаешься архитектурой.
В программе:
— мультиагентные системы в CrewAI: делегирование рутины и контроль логики;
— сложная логика в LangGraph: стейт-менеджмент и работа с графами;
— tool use интеграция: связь агентов с вашим API, БД и облаком. ⚡️
Записаться на курс
⭐️ Нестандартные форматы резюме для шарписта
Рынок IT вакансий в 2026 году переполнен кандидатами с похожими PDF резюме. Рекрутеры тратят на просмотр отклика секунды, и стандартный формат часто теряется в потоке.
Новые форматы самопрезентации помогают выделиться и сразу показать навыки разработчика. Например, резюме в виде changelog'а.
➡️ Все 6 форматов в статье
Если стандартное резюме не приносит откликов, имеет смысл попробовать хотя бы один из нестандартных форматов и добавить его к привычному PDF.
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
❓ Что выведет код
Не спешите отвечать, код вполне может содержать намеренные ошибки. На интервью ценят скорость, но лучше ответить без ошибок.
Посмотреть ответ 👉 в нашем канале
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#dotnet_challenge
👨💻 ToLookup для поиска дубликатов
ToLookup — это не только группировка данных. Метод создаёт индексированную структуру, что делает его быстрой альтернативой GroupBy в некоторых сценариях.
Допустим, у вас есть список чисел и нужно найти те, что встречаются больше одного раза.
Стандартный подход через GroupBy:
public static IEnumerable<int> FindDuplicates_GroupBy(List<int> data)
{
return data.GroupBy(x => x)
.Where(g => g.Count() > 1)
.Select(g => g.Key);
}
GroupBy выполняется лениво — при каждой итерации происходит перегруппировка.public static IEnumerable<int> FindDuplicates_Lookup(List<int> data)
{
var lookup = data.ToLookup(x => x);
return lookup.Where(g => g.Count() > 1)
.Select(g => g.Key);
}
Почему так сложно просто принять оплату❓
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#garbage_collector
🗑 Soft Delete в базах данных
Многие проекты добавляют в таблицы колонку deleted или archived_at, чтобы не удалять данные окончательно. Звучит удобно: пользователь случайно что-то удалил — можно восстановить. Но на практике это создаёт массу проблем.
Основные проблемы классического подхода
Мёртвые данные в живых таблицах. 99% архивных записей никогда не будут прочитаны, но они постоянно болтаются рядом с актуальными данными.
Каждый запрос должен фильтровать WHERE archived_at IS NULL. Индексы раздуваются. Миграции данных становятся сложнее — надо ли обрабатывать записи двухлетней давности? Всегда есть риск, что архивные данные случайно попадут туда, где их быть не должно.
Создание записи затрагивает внешние системы. Восстановление может требовать сложной логики, которая всегда будет неполной копией API создания. Старые данные могут не пройти новые правила валидации.
Альтернативные подходы
• Архивирование на уровне приложения
При удалении записи приложение отправляет событие в очередь, а отдельный сервис сохраняет архивные данные в другом месте.
Плюсы: основная БД остаётся простой, удаление асинхронное (быстрее и надёжнее), данные можно сериализовать в удобном формате.
Минусы: легко допустить баг и потерять архивные данные, больше инфраструктуры, сложнее искать записи для восстановления.
• Триггеры PostgreSQL
Создаём универсальную таблицу archive, которая хранит JSON-представление удалённых записей:
CREATE TABLE archive (
id UUID PRIMARY KEY,
table_name TEXT NOT NULL,
record_id TEXT NOT NULL,
data JSONB NOT NULL,
archived_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
Интеграция LLM в .NET: подходы RAG и Fine-tuning
23 января в 19:00 обсудим создание интеллектуальных ассистентов на открытом уроке к курсу «Разработка ИИ агентов». Разберём, как реализовать контекстный поиск по вашим документам и когда стоит прибегать к дообучению моделей.
Спикер — Игорь Стурейко, тимлид в «Газпроме» и эксперт с 20-летним опытом в ML. Игорь подготовил видеосообщение, в котором рассказывает о переходе от чат-ботов к автономным агентам и архитектуре будущей программы.
Ключевые темы:
— использование RAG для ответов по внутренней документации;
— фреймворки уровня LangChain и LlamaIndex в Enterprise-среде;
— работа с хранилищами векторных эмбеддингов (FAISS, Chroma).
📅 Когда: 23.01 в 19:00 МСК
Узнать подробности
🧬 Мутационное тестирование
Вы пишете unit-тесты, coverage показывает 80-90%, но уверены ли вы, что эти тесты реально ловят баги? Мутационное тестирование помогает проверить качество самих тестов.
Суть подхода
Инструмент автоматически вносит небольшие изменения в ваш код: меняет операторы, условия, константы. Если тесты проходят с «поломанным» кодом — значит, они недостаточно строгие.
Stryker.NET в действии
Установка занимает пару минут через dotnet tool. После запуска Stryker анализирует код, создаёт мутантов и прогоняет по ним тесты. В отчёте вы видите:
• Какие мутации выжили
• Mutation Score — процент убитых мутантов
• Конкретные строки кода, где тесты слабые
Практический пример
Допустим, у вас метод проверяет возраст пользователя. Stryker меняет age >= 18 на age > 18. Если тест с граничным значением 18 отсутствует — мутант выживает, и вы понимаете, где дописать проверку.
Stryker умеет работать с xUnit, NUnit, MSTest. Настраивается через JSON-файл, где можно указать пороговые значения mutation score, исключить файлы из анализа, настроить уровни логирования.
Процесс требует времени — каждая мутация прогоняет весь набор тестов. Но результат того стоит: вы находите слепые зоны в тестовом покрытии, которые обычный coverage не показывает.
➡️ Репозиторий
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#il_люминатор
👍 JIT .NET 10 убирает абстракции почти бесплатно
В .NET 10 Microsoft сильно доработали JIT компилятор. Цель простая сделать так, чтобы привычный высокоуровневый С# код работал почти как вручную вылизанный низкоуровневый.
Главная идея обновления JIT убрать лишнюю цену за высокоуровневые конструкции. Раньше интерфейсы, делегаты, итераторы легко приносили дополнительные аллокации и лишнюю индирекцию, сейчас JIT старается пробиться сквозь них к конкретным типам и генерировать более плотный машинный код.
Ключевой механизм это улучшенный escape analysis. Если JIT может доказать, что объект живет только внутри метода не передается наружу и не сохраняется в поля, он размещает его на стеке.
Пример:
[Benchmark]
[Arguments(42)]
public int SumWithOffset(int offset)
{
Func<int, int> addOffset = value => value + offset;
return ApplyTwice(addOffset, offset);
}
🚀 Одна строка кода для ускорения EF Core
Когда EF Core загружает связанные сущности через Include(), он генерирует один огромный SQL-запрос с множеством JOIN. Результат? Тысячи дублирующихся строк, гигабайты трафика и медленная работа.
Пример:
var posts = await context.Posts
.Include(p => p.Comments)
.ThenInclude(c => c.Reactions)
.ToListAsync();
.AsSplitQuery() — и EF Core разобьёт один большой запрос на несколько маленьких:var posts = await context.Posts
.AsSplitQuery() // ← магия здесь
.Include(p => p.Comments)
.ThenInclude(c => c.Reactions)
.ToListAsync();
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#garbage_collector
🧑💻 Исключения — не для обычного управления потоком
Исключения во флоу — это не просто дорогие операции. Они дороги когнитивно: затуманивают логику программы и размывают границу между ошибкой и нормальным поведением.
Антипаттерн, который всё ещё встречается:
{
var value = dictionary[key];
Process(value);
}
catch (KeyNotFoundException)
{
// ignore
}if (dictionary.TryGetValue(key, out var value))
{
Process(value);
}
👨💻 Когда if начинает распухать
Паттерн стратегия подходит, когда один и тот же сценарий можно выполнить несколькими способами, и выбор зависит от условий. Вместо большого switch внутри сервиса разные варианты выносятся в отдельные классы с общим интерфейсом, а контекст просто делегирует работу выбранной реализации.
Типовая схема такая. Есть интерфейс Strategy, есть несколько конкретных стратегий, и есть контекст, который держит ссылку на стратегию и вызывает ее метод, не зная деталей реализации. Это снижает связность и позволяет добавлять новые варианты без переписывания старого кода.
Мини пример на C#:
public interface IDiscountStrategy
{
decimal Apply(decimal total);
}
public sealed class RegularDiscount : IDiscountStrategy
{
public decimal Apply(decimal total) => total;
}
public sealed class VipDiscount : IDiscountStrategy
{
public decimal Apply(decimal total) => total * 0.9m;
}
public sealed class Checkout
{
private readonly IDiscountStrategy _discount;
public Checkout(IDiscountStrategy discount) => _discount = discount;
public decimal TotalWithDiscount(decimal total) => _discount.Apply(total);
}
var checkout = serviceProvider.GetRequiredService<Checkout>();
var total = checkout.TotalWithDiscount(100m);
⚡️ Урок про боксинг в C#
Разбираем типичную ошибку, которая встречается даже в коде крупных проектов.
Код с подвохом:
struct StackValue
{
public override bool Equals(object obj)
{
if (Object.ReferenceEquals(this, obj))
return true;
if (!(obj is StackValue))
return false;
var value = (StackValue)obj;
return this.Kind == value.Kind
&& this.Flags == value.Flags
&& this.Type == value.Type;
}
}
ReferenceEquals принимает параметры типа object. Когда вы передаёте структуру, происходит боксинг: значение копируется в хип и оборачивается объектом.Equals:
🟥 Новостной дайджест
Выходные выходными, но новости должны быть по расписанию.
— Быстрая загрузка Windows 95
— NBomber 6.2.0
— Ghostty почти запретил ИИ-генерированный код
Разработчик терминала Ghostty Митчелл Хашимото ужесточил правила: теперь любой PR с кодом от ИИ вроде Claude или Cursor требует раскрытия использования модели, полного тестирования человеком и предварительного одобрения issues, а нарушителей грозит бан и публичное осмеивание.
— Microsoft выпустили WinApp
Новый открытый инструмент WinApp CLI упрощает жизнь разработчикам на кросс-платформенных фреймворках вроде Electron, Rust или Dart, избавляя от ручной настройки SDK, манифестов, сертификатов и упаковки в MSIX.
— Chrome в Windows 11 скоро позволит перетаскивать несколько файлов из веб-приложений в Проводник
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#async_news
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#garbage_collector
📄 Забытое искусство XML
Наткнулись на статью, которая ставит под сомнение один из главных технологических трендов последних лет — отказ от XML в пользу JSON.
XML был отвергнут не из-за технической неполноценности, а потому что победил JavaScript.
Что мы потеряли, отказавшись от XML:
• Схемы и валидация — XSD позволяет проверять типы и структуру данных на уровне документа, до парсинга. JSON Schema существует, но это сторонняя надстройка, которая так и не стала стандартом.
• Пространства имён — можно комбинировать документы из разных схем без конфликтов. В JSON приходится импровизировать с префиксами.
• Комментарии — в XML они есть изначально. JSON их запрещает, потому что они усложняют парсинг.
• Самодокументирование — XML-документ содержит или явно ссылается на свою схему. В JSON приходится гадать, что значит "status": 1.
Вместо того чтобы использовать XML, мы потратили миллиарды на создание библиотек валидации, TypeScript, генераторов API-клиентов — по сути, воссоздавая то, что уже было в XML.
Microsoft, несмотря на все критику, продолжали использовать XML для MSBuild, WPF, и системы конфигурации .NET Framework. Переход на JSON в .NET Core случился не потому что XML был плох, а под давлением модных трендов.
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#il_люминатор
Пятница, 19:00. Худшее время для деплоя, но идеальное, чтобы наконец подружить .NET-приложение с нейронками через современные RAG-инструменты.
Как интегрировать LLM в проект и заставить её работать с вашими специфичными данными? Разберёмся на примере концепции RAG.
Программа открытого урока:
— сравнение RAG и Fine-tuning: архитектурный выбор;
— работа с векторными БД и эмбеддингами;
— демонстрация пайплайна, который «читает» документацию в PDF.
Один из спикеров — Алексей Яндутов, ML-инженер в поиске Яндекса.
Это вводное занятие к большому курсу «Разработка AI-агентов». Мы ориентируемся на разработчиков, а не на «промпт-инженеров».
Записаться на урок
💡 Старый трюк Windows 95 с Shift
В Windows 95 был странный эффект если перезагружать систему с зажатым Shift появлялась надпись Windows is restarting и перезапуск занимал заметно меньше времени. Для многих это выглядело как полумистический хак хотя на самом деле там работала вполне конкретная логика в старом 16 битном коде.
При обычном перезапуске Windows 95 инициировала полноценный холодный ребут то есть машина проходила полный цикл начальной инициализации BIOS и заново загружала систему из нуля.
При перезапуске с зажатым Shift вместо этого вызывался старый 16 битный ExitWindows с специальным EW флагом который говорил ядру не перезагружать железо а только выгрузить саму Windows и вернуться.
➡️ Источник
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#async_news
🤓 Группировка данных без лишних действийToLookup — это метод LINQ, который группирует элементы коллекции по ключу. Похож на GroupBy, но есть важные отличия, которые делают его удобным в определённых ситуациях.
— Как работает ToLookup
Метод создаёт структуру данных ILookup<TKey, TElement> — это неизменяемая коллекция групп. Каждая группа содержит элементы с одинаковым ключом.
var users = new[]
{
new { Name = "Anna", Department = "Dev" },
new { Name = "Boris", Department = "Dev" },
new { Name = "Clara", Department = "QA" }
};
var lookup = users.ToLookup(u => u.Department);
foreach (var user in lookup["Dev"])
{
Console.WriteLine(user.Name); // Anna, Boris
}
lookup["Dev"]. Если ключа нет — вернётся пустая последовательность, а не исключение.GroupBy возвращает IEnumerable<IGrouping<TKey, TElement>> — это отложенное выполнение. Группировка происходит при каждой итерации.ToLookup выполняется немедленно и возвращает готовую структуру в памяти. Это значит:ToLookupGroupBy эффективнее
🙂 Подборка вакансий для шарпистов
C# Developer — удалёнка в Ростиксе.
.NET разработчик — долларовая удалёнка.
Senior Unity Developer Teamlead — до 400 000 ₽ на гибрид в Москву.
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
🔄 NBomber 6.2.0: фильтрация метрик, OpenTelemetry и улучшенные отчёты
NBomber — это фреймворк для распределённого нагрузочного тестирования в .NET. Вы пишете сценарии на обычном C# или F#, тестируете любые системы независимо от протокола и модели взаимодействия.
Что нового в версии 6.2.0:
Теперь можно фильтровать метрики по имени — полезно, когда у вас десятки показателей. На графике Throughput отображается Fail RPS, так что проблемы видны сразу.
Кластерный режим теперь настраивается через CLI без JSON-конфига. Можно указать целевые сценарии, а группы агентов стали опциональными.
Реализована интеграция с OpenTelemetry — теперь метрики можно отправлять в стандартные системы мониторинга.
➡️ Релиз на GitHub
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#async_news
📎 Преобразование Excel в JSON
Сделаем минимальный код для чтения таблиц для конвертации в JSON.
Подключите NuGet-пакеты FreeSpire.XLS и Newtonsoft.Json. Первая читает .xlsx без зависимостей, вторая формирует JSON.
Код начинается с загрузки файла в поток. Библиотека преобразует лист в DataSet, где строки становятся объектами. Первая строка служит заголовками полей.
Чтение и конвертация данных:
using Spire.Xls;
using Newtonsoft.Json;
Workbook wb = new Workbook();
wb.LoadFromFile("данные.xlsx");
DataTable таблица = wb.Worksheets.ExportDataTable();
JsonSerializerSettings опции = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
NullValueHandling = NullValueHandling.Ignore
};
string результат = JsonConvert.SerializeObject(таблица, опции);
File.WriteAllText("выход.json", результат);
🛠 Parallel.For — когда циклы работают параллельно
Представьте: у вас есть массив из миллиона элементов, и каждый нужно обработать. Обычный цикл for будет делать это последовательно — один элемент за другим. А что если задействовать все ядра процессора?
Базовое использование:
// Было
for (int i = 0; i < 1000; i++)
{
ProcessImage(images[i]);
}
// Стало
Parallel.For(0, 1000, i =>
{
ProcessImage(images[i]);
});
public const Price = OldPrice; // до 20.01
Мы меняем значение константы: завтра обучение станет дороже. Успейте пробросить заказ сегодня, чтобы зафиксировать текущую стоимость в своём стеке.
Инициализировать рост компетенций
👼 Дайджест первой недели
Прошла первая рабочая неделя 2026 года. Собираем яркие материалы и новости в один пост.
— Microsoft показали как делать виджеты
— Удаляем хлам из браузера
— Новая база корпоративной культуры
— Январские обновления .NET
— Скоро будет домен .meow
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#async_news
🔄 .NET: январские обновления
Microsoft выпустила очередную порцию сервисных обновлений для платформы .NET. Вышли новые версии для трёх поддерживаемых веток:
.NET 10.0.2 — самая свежая версия платформы
.NET 9.0.12 — актуальная STS-версия
.NET 8.0.23 — предыдущая LTS-версия
➡️ Блог разработчиков
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#async_news
«Этот манёвр будет стоить нам 51 год...»
Для .NET разработчика архитектура и алгоритмы — это база. Если вы хотите проектировать сложные системы или внедрять ИИ в свои энтерпрайз-решения, сейчас лучший момент для старта.
В Proglib Academy поднимаются цены. Успейте забрать курс по старой стоимости:
— Разработка ИИ-агентов
— Математика для разработки AI-моделей
— ML для старта в Data Science
— Математика для Data Science
— Специалист по ИИ
— Алгоритмы и структуры данных
— Программирование на Python
— Основы IT для непрограммистов
— Архитектуры и шаблоны проектирования
Забрать по старой цене
⚠️ Повышение уже 19 января