fa
Feedback
C# 1001 notes

C# 1001 notes

رفتن به کانال در Telegram

Регулярные короткие заметки по C# и .NET. Просто о сложном для каждого. admin - @haarrp

نمایش بیشتر
6 608
مشترکین
+324 ساعت
+527 روز
+4030 روز
آرشیو پست ها
⚡️ Миграция хеширования паролей без поломки логина Ты сделал маленький и вроде бы аккуратный рефакторинг - и сломал весь логи
⚡️ Миграция хеширования паролей без поломки логина Ты сделал маленький и вроде бы аккуратный рефакторинг - и сломал весь логин. Логику хеширования паролей ты аккуратно вынес в отдельный слой. Отлично. А потом решил обновиться — заменить PBKDF2 на bcrypt. Просто поменял реализацию. Казалось бы, безопасно. Но внезапно: - старые пользователи больше не могут войти - пароли перестали совпадать - аутентификация массово падает Ты только что внёс breaking change, даже не заметив этого. Это классическая ловушка в аутентификации — менять алгоритм хеширования без стратегии миграции. Важно понимать: - пароли в базе уже захешированы старым алгоритмом - новый алгоритм не умеет их проверять - простой swap реализации = мгновенный outage - ⚡️Правильный подход: - поддерживать несколько алгоритмов одновременно - определять алгоритм по формату хеша - при успешном логине пересохранять пароль новым алгоритмом - без сброса паролей - без даунтайма Маленькие изменения в use case-ах, особенно в аутентификации, могут иметь огромные последствия.

Есть соглашения по именованию в коде, которые все постоянно нарушают? Имена классов, слоёв, обработчиков, сервисов - это част
Есть соглашения по именованию в коде, которые все постоянно нарушают? Имена классов, слоёв, обработчиков, сервисов - это часть архитектуры. Но обычно всё держится на: • договорённостях в голове • комментариях в Wiki “ну мы же так решили” А потом кто-то добавляет UserCmdHandler, DoStuffManager или NewService2 - и структура просто разваливается. 💡 Решение: архитектурные тесты Вы можете написать тесты, которые проверяют саму архитектуру, а не бизнес-логику. Например:все CommandHandler обязаны заканчиваться на CommandHandler • классы из Application не должны ссылаться на Infrastructure • контроллеры не имеют доступа к репозиториям напрямую DTO не должны жить в доменной модели И если кто-то нарушил правило - тест падает. Сразу. В CI. ⚙️ Что это даёт Архитектура перестаёт быть кривой и косой. Она начинает подчиняться строгим правилам. Новый разработчик в команде может не знать всех договорённостей, но код всё равно останется чистым, потому что правила защищены тестами. 🧠 Главное осознание Архитектурные тесты защищают структуру. А структура - это то, что определяет, станет проект поддерживаемым… или превратится в хаос через год.

🖥 Если ты делаешь бэкенд на .NET и хочешь расти не «по туториалам», а в сторону прод-уровня, архитектуры и реальных систем - это золото. Архитектура и структура проектов N-Layered vs Clean vs Vertical Slice Architecture https://antondevtips.com/blog/n-layered-vs-clean-vs-vertical-slice-architecture Лучшая структура .NET-проектов с Clean Architecture и Vertical Slices https://antondevtips.com/blog/the-best-way-to-structure-your-dotnet-projects-with-clean-architecture-and-vertical-slices Зачем писать архитектурные тесты https://antondevtips.com/blog/why-do-you-need-to-write-architecture-tests-in-dotnet От модульного монолита к микросервисам https://antondevtips.com/blog/migrating-modular-monolith-to-microservices-in-dotnet API и бэкенд-практики Best Practices для REST API https://antondevtips.com/blog/best-practices-for-building-rest-apis 90% API не RESTful - что вы упускаете https://antondevtips.com/blog/90-of-apis-are-not-restful-what-youre-missing-and-when-it-matters Как ускорить Web API https://antondevtips.com/blog/how-to-increase-performance-of-web-apis-in-dotnet Аутентификация и авторизация в ASP.NET Core https://antondevtips.com/blog/authentication-and-authorization-best-practices-in-aspnetcore Интеграционные тесты в ASP.NET Core https://antondevtips.com/blog/asp-net-core-integration-testing-best-practises EF Core и данные Почему не нужен Repository поверх EF Core https://antondevtips.com/blog/why-you-dont-need-a-repository-in-ef-core 5 скрытых NuGet-пакетов для EF Core https://antondevtips.com/blog/5-hidden-efcore-nuget-packages Кеширование в .NET https://antondevtips.com/blog/how-to-implement-caching-strategies-in-dotnet Resilience, инфраструктура, прод Retry и устойчивость с Polly и Microsoft Resilience https://antondevtips.com/blog/how-to-implement-retries-and-resilience-patterns-with-polly-and-microsoft-resilience Загрузка больших файлов в Azure Blob Storage https://antondevtips.com/blog/implementing-large-file-uploads-and-downloads-in-azure-blob-storage-with-dotnet Деплой в Azure с Neon Postgres и .NET Aspire https://antondevtips.com/blog/how-to-deploy-dotnet-application-to-azure-using-neon-postgres-and-dotnet-aspire Job Scheduler TickerQ https://antondevtips.com/blog/tickerq-the-modern-dotnet-job-scheduler-that-beats-quartz-and-hangfire Observability Старт с OpenTelemetry, Jaeger и Seq https://antondevtips.com/blog/getting-started-with-open-telemetry-in-dotnet-with-jaeger-and-seq Код и язык Как писать чище и лучше код в .NET https://antondevtips.com/blog/how-to-write-better-and-cleaner-code-in-dotnet Новые фичи .NET 10 и C# 14 https://antondevtips.com/blog/new-features-in-dotnet-10-and-csharp-14 Extension Members в C# 14 https://antondevtips.com/blog/extension-members-in-csharp14-changed-how-we-write-code-forever Практические проекты Invoice Builder на .NET с IronPDF https://antondevtips.com/blog/how-to-build-a-production-ready-invoice-builder-in-dotnet-using-ironpdf Ошибки разработчиков Top 10 вещей, которые должен делать .NET-разработчик в 2026 https://antondevtips.com/blog/top-10-things-every-dotnet-developer-needs-to-do-in-2026 15 ошибок .NET-разработчиков https://antondevtips.com/blog/top-15-mistakes-dotnet-developers-make-how-to-avoid-common-pitfalls 15 ошибок при создании Web API https://antondevtips.com/blog/top-15-mistakes-developers-make-when-creating-web-apis Это не «почитать на досуге». Это roadmap от уровня “пишу контроллеры” до “проектирую систему, которая живёт в проде годами”.

⚙️ Вы настраиваете ASP.NET Core «по наитию» и тратите время на поиск, почему приложение ведет себя по-разному в продакшене и локально? 📆 29 января в 20:00 OTUS проводит открытый урок «Конфигурирование приложения ASP.NET Core» в преддверии старта курса «C# ASP.NET Core разработчик». На занятии разберем, как выстроить прозрачную и управляемую систему настроек: appsettings.json, провайдеры конфигурации, приоритет применения конфигураций, настройки специфичные для среды и шаблон Options для работы с настройками. Вы поймете, как проектировать конфигурации так, чтобы приложения были стабильными и предсказуемыми. ❗️Урок будет полезен разработчикам ASP.NET Core начального и среднего уровня, которые хотят систематизировать знания и работать по индустриальным стандартам. ➡️ Регистрируйтесь на бесплатный урок: https://tglink.io/0180da777d54?erid=2W5zFH1uFyz 🎁 Все участники открытого урока получат скидку на обучение. #реклама О рекламодателе

✔️ C# может прокачать collection expressions: “аргументы при создании коллекции” Есть прикольное предложение в csharplang: сд
✔️ C# может прокачать collection expressions: “аргументы при создании коллекции” Есть прикольное предложение в csharplang: сделать так, чтобы в collection expressions (`[a, b, c]`) можно было передавать аргументы в создание коллекции. Проблема сейчас: Postgres-стайл удобный синтаксис уже есть: List<int> xs = [1, 2, 3]; Но если тебе важно задать, например, capacity (чтобы не было лишних realloc внутри списка), то приходится писать “старым способом”: var xs = new List<int>(capacity: 32) { 1, 2, 3 }; Предлагаемое решение: добавить возможность передавать аргументы прямо в collection expression: List<int> xs = [args(capacity: 32); 1, 2, 3]; То есть: - args(...) - это аргументы для конструктора / create-метода - после ; - элементы коллекции Зачем это нужно: - можно сохранить суперкороткий синтаксис [ ... ] - но при этом контролировать создание коллекции (capacity, comparer и т.д.) - меньше лишних аллокаций → быстрее в hot-path коде Если фича дойдёт до релиза, это будет реально удобный апгрейд синтаксиса коллекций в C#. https://github.com/dotnet/csharplang/blob/main/proposals/collection-expression-arguments.md

🖥 Многопоточность в .NET часто сводят к lock. Но в реальных системах этого недостаточно — особенно под нагрузкой, в легаси-коде и распределённых сценариях. 📕 На открытом уроке разберём, какие инструменты действительно есть в .NET и как выбирать подходящий примитив под конкретную задачу. Рассмотрим Monitor, Mutex, Semaphore, а также другие примитивы из System.Threading: ReaderWriterLockSlim, Barrier, ManualResetEventSlim, SpinLock. ❗️ Вы увидите практические примеры, типовые ошибки и узнаете, где блокировки становятся узким местом. Урок будет полезен разработчикам, работающим с высоконагруженными системами и легаси-кодом, а также тимлидам, которые проектируют архитектуру и отвечают за производительность. 📣 Встречаемся 27 января в 20:00 МСК в преддверии старта курса «C# Developer. Professional». Регистрация открыта: https://otus.pw/t6Xj/

✅ API Input Validation в .NET: почему FluentValidation лучше, чем Data Annotations Data Annotations отлично подходят для прос
✅ API Input Validation в .NET: почему FluentValidation лучше, чем Data Annotations Data Annotations отлично подходят для простых правил: [Required] - ок [MaxLength(50)] - норм Но как только тебе нужно что-то “умнее”, начинается боль: - проверить данные в базе - валидировать по настройкам из appsettings.json - вызвать сервис и принять решение динамически Data Annotations упираются в потолок, потому что Attribute - это статичная штука. Туда не получится нормально прокинуть зависимости через DI. И вот здесь FluentValidation реально сияет ✨ Почему: FluentValidation-валидаторы - это обычные классы, которые регистрируются в DI контейнере. А значит, внутрь можно инжектить что угодно: - сервисы - конфиги - репозитории - кэш - внешние API Пример: нужно проверить, что CouponCode валиден через IPricingService? Просто инжектишь IPricingService в конструктор валидатора и делаешь проверку. В итоге валидация превращается из “статической проверки полей” в полноценный слой логики - динамический, умный и расширяемый. FluentValidation = правильная валидация для реального продакшена.

🤖 Open Claude Cowork: AI-партнёр для программирования Open Claude Cowork — это настольный AI-ассистент, который помогает в п
🤖 Open Claude Cowork: AI-партнёр для программирования Open Claude Cowork — это настольный AI-ассистент, который помогает в программировании, управлении файлами и выполнении задач. Он совместим с Claude Code и предлагает визуальный интерфейс для удобной работы с AI, позволяя легко управлять сессиями и получать результаты в реальном времени. 🚀Основные моменты: - 🖥️ Настольное приложение с визуальным интерфейсом - 🤖 AI-партнёр для выполнения задач - 🔁 Полная совместимость с Claude Code - 📂 Удобное управление сессиями и историей - 🔐 Контроль разрешений для безопасных действий 📌 GitHub: https://github.com/DevAgentForge/Claude-Cowork

⚡️ Автоматическая регистрация Minimal APIs в .NET - без ручного маппинга Если в проекте 20+ endpoint’ов, app.MapGet/MapPost п
⚡️ Автоматическая регистрация Minimal APIs в .NET - без ручного маппинга Если в проекте 20+ endpoint’ов, app.MapGet/MapPost превращается в ад. Решение - авторегистрировать endpoints через DI. Идея: 1) Делаешь общий интерфейс IEndpoint 2) Каждый endpoint реализует его 3) На старте приложения сканируешь сборку, регистрируешь все реализации в DI 4) Достаёшь их из DI и вызываешь MapEndpoints() Плюсы: ✅ чистый Program.cs ✅ каждый endpoint в отдельном файле ✅ масштабируется без хаоса ✅ легко тестировать и поддерживать Пример паттерна:

builder.Services.AddEndpoints(typeof(Program).Assembly);

public interface IEndpoint
{
    void Map(IEndpointRouteBuilder app);
}

public static class EndpointExtensions
{
    public static IServiceCollection AddEndpoints(this IServiceCollection services, Assembly assembly)
    {
        var endpoints = assembly.DefinedTypes
            .Where(t => !t.IsAbstract && !t.IsInterface && typeof(IEndpoint).IsAssignableFrom(t))
            .Select(t => ServiceDescriptor.Transient(typeof(IEndpoint), t))
            .ToArray();

        services.TryAddEnumerable(endpoints);
        return services;
    }

    public static void MapEndpoints(this WebApplication app)
    {
        foreach (var endpoint in app.Services.GetServices<IEndpoint>())
            endpoint.Map(app);
    }
}

✔️ C# стал языком 2025 года по версии TIOBE. Индекс TIOBE подвел итоги года: звание «Язык 2025 года» досталось C#, который по
✔️ C# стал языком 2025 года по версии TIOBE. Индекс TIOBE подвел итоги года: звание «Язык 2025 года» досталось C#, который показал рекордный рост популярности (+2.94%)? однако в общем зачете он по-прежнему занимает 5-ю строчку. Абсолютным лидером остается Python с 22.61% долей рынка. В первой пятерке произошли перестановки: язык C поднялся на 2 место, сместив C++ на 4-ю позицию; 3 место досталось Java, а R вернулся в топ-10. Провал года - Go, который неожиданно сдал позиции, опустившись сразу на 16-е место. Индекс оценивает популярность технологий на основе поисковых запросов, активности комьюнити и количества обучающих материалов. https://www.tiobe.com/tiobe-index/

🔥 На stepik вышел курс, который учит Создавать настоящие AI-сервисы, а не просто запускать скрипты? Этот практический курс п
🔥 На stepik вышел курс, который учит Создавать настоящие AI-сервисы, а не просто запускать скрипты? Этот практический курс по Python и FastAPI покажет, как собрать полноценное приложение с ИИ, базой данных, автогенерацией контента и Telegram-ботом. Ты пройдёшь путь от первого HTTP-запроса до рабочего сервиса, который сам генерирует текст через ИИ, сохраняет данные, отправляет результаты по расписанию и отвечает пользователям. Никакой теории ради теории - только практические шаги, из которых рождается реальный продукт. 🎁 48 часов действует скидка в 40% процентов 👉 Начать учиться на Stepik

3 простые оптимизации, которые реально ускоряют код 1️⃣ Забирай данные пачкой Меньше запросов — меньше сетевых задержек. Вмес
3 простые оптимизации, которые реально ускоряют код 1️⃣ Забирай данные пачкой Меньше запросов — меньше сетевых задержек. Вместо десятков запросов — один IN (...). 2️⃣ Делай больше параллельно Если задачи не зависят друг от друга — выполняй их одновременно. Асинхронность часто даёт бесплатный прирост скорости. 3️⃣ Кэшируй результаты Если данные не меняются — не пересчитывай и не запрашивай их заново. Память дешевле времени. Никакой магии и сложных алгоритмов — просто базовые приёмы, которые в реальных проектах дают самый заметный эффект.

🔥 Последний шанс: набор на курс Highload Architect в этом году завершается! 🚀 Если хотите перейти от разработки к архитекту
🔥 Последний шанс: набор на курс Highload Architect в этом году завершается! 🚀 Если хотите перейти от разработки к архитектуре высоконагруженных систем — действуйте сейчас. Чтобы попасть в поток и зафиксировать спеццену, нужно успеть пройти вступительное тестирование до закрытия набора. Вы сможете прокачать: • Проектирование масштабируемых систем под миллионы запросов • Оптимизацию производительности и отказоустойчивые архитектуры • Практику с современными инструментами highload-разработки • Применение проверенных паттернов и подходов в продакшене 🗓 Старт уже совсем скоро, места ограничены. Формат — онлайн, реальные кейсы, проект с защитой и детальный фидбек от практиков. 👉 Пройдите вступительное тестирование прямо сейчас: https://otus.pw/m5B0/?erid=2W5zFHPuxbJ Реклама. ООО "ОТУС ОНЛАЙН-ОБРАЗОВАНИЕ". ИНН 9705100963.

🔥 Как правильно работать с конфигурацией в .NET Самый чистый и масштабируемый способ получать настройки в .NET - это Options
🔥 Как правильно работать с конфигурацией в .NET Самый чистый и масштабируемый способ получать настройки в .NET - это Options pattern. Где живет конфигурация Настройки приложения могут приходить из разных источников: - переменные окружения - JSON-файлы appsettings - user secrets - другие configuration providers Да, можно читать значения напрямую через IConfiguration. Но это плохо масштабируется: - легко ошибиться в ключе - нет типизации - нет валидации - код быстро превращается в хаос Поэтому IConfiguration напрямую лучше не использовать в бизнес-коде. Options pattern - как правильно Вместо этого используется Options pattern: 1. Создаешь класс настроек - один класс = одна логическая группа конфигурации 2. Биндишь его к appsettings.json - через services.Configure<T> 3. Используешь настройки через DI - IOptions - IOptionsSnapshot - IOptionsMonitor Плюсы подхода - строгая типизация - автокомплит в IDE - централизованная конфигурация - проще рефакторить - можно добавить валидацию через data annotations Например: - [Required] - [Range] - [EmailAddress] Это позволяет ловить ошибки конфигурации при старте приложения, а не в продакшене. Важно знать Существуют разные интерфейсы: - IOptions - статические настройки на все время жизни приложения - IOptionsSnapshot - обновляются на каждый запрос (scoped) - IOptionsMonitor - отслеживают изменения конфигурации в рантайме Понимание разницы между ними сильно влияет на корректность архитектуры. Если пишешь production .NET - Options pattern должен быть стандартом по умолчанию. https://www.milanjovanovic.tech/blog/how-to-use-the-options-pattern-in-asp-net-core-7

🛠 Как оживить протухшую ветку без merge-хаоса Бывает: вы увлеклись разработкой, прошло пару недель (или месяцев), а основная ветка уже ушла далеко вперёд. В итоге — боль, конфликты и бесконечные merge-коммиты. В таких случаях может спасати ребейз на свежую ветку:

git pull --rebase origin release/1.2.0
Она подтянет последние изменения из релизной ветки и наложит ваши коммиты поверх, сохранив линейную историю. Конфликты всё равно придётся разруливать, но по одному — в контексте конкретного коммита, а не в гигантской свалке. После успешного ребейза пушим с --force-with-lease, чтобы аккуратно обновить удалённую ветку, и продолжаем работать так, как будто отставания и не было.

🧠 Polyglot Persistence: как современные системы живут с десятками баз данных 🔥 23 декабря в 20:00 мск — открытый вебинар в
🧠 Polyglot Persistence: как современные системы живут с десятками баз данных 🔥 23 декабря в 20:00 мск — открытый вебинар в OTUS. Одна база данных больше не справляется с требованиями современного мира. Сегодня компании вроде Avito, Yandex, Ozon и Spotify объединяют PostgreSQL, ClickHouse, Redis, Kafka, Elasticsearch и десятки других инструментов в единую экосистему, где каждая БД отвечает за свой кусочек производительности. 📌 На вебинаре разберём: — Принципы Polyglot Persistence и как распределять роли между СУБД — Как связать PostgreSQL, ClickHouse, Redis и Kafka без потери согласованности — Как работают event-driven архитектуры, CDC и outbox-паттерн в боевых системах — Как проектировать отказоустойчивые data-платформы Регистрация https://otus.pw/enVW/?erid=2W5zFHSfqbE Бесплатное занятие приурочено к старту курса Highload Architect, где вы научитесь проектировать системы, выдерживающие миллионы запросов. Реклама. ООО "ОТУС ОНЛАЙН-ОБРАЗОВАНИЕ". ИНН 9705100963.

🚦 Feature Flags в .NET - как управлять релизами без redeploy Feature flags (фиче-флаги) позволяют включать и выключать функц
🚦 Feature Flags в .NET - как управлять релизами без redeploy Feature flags (фиче-флаги) позволяют включать и выключать функциональность на лету, без повторного деплоя и риска для продакшена. Идея простая: код задеплоен → поведение управляется конфигурацией. Что это даёт на практике: — Постепенные релизы Можно включить новую фичу сначала для 1%, 10% или конкретной группы пользователей. — Быстрый rollback Если что-то пошло не так — просто выключаете флаг. Без откатов и срочных хотфиксов. — A/B тесты Разные пользователи получают разное поведение одного и того же кода. — Targeting пользователей Фичи можно включать: • по user id • по роли • по региону • по environment (dev / staging / prod) — Меньше фиче-веток Код живёт в main, а не за флагами в git. В .NET обычно используют: - Microsoft.FeatureManagement - Azure App Configuration - LaunchDarkly / Unleash / ConfigCat Где это особенно полезно: - публичные API - high-traffic сервисы - SaaS-продукты - экспериментальные и рискованные фичи Коротко: Feature flags превращают релиз из «одного опасного момента» в управляемый процесс. Это один из самых мощных инструментов для зрелой backend-архитектуры. 👉 Подробнее

Крутая статья - «Building an Event Queue in ASP.NET Core» от Deepumi. 🔹 Она показывает, как правильно построить очередь собы
Крутая статья - «Building an Event Queue in ASP.NET Core» от Deepumi. 🔹 Она показывает, как правильно построить очередь событий внутри ASP.NET Core-приложения: • использовать встроенные механизмы (middleware / DI) • распределять события между обработчиками • обрабатывать события асинхронно и надёжно 🔹 Такая архитектура помогает: • реализовать decoupled компоненты, которые не знают друг о друге • централизовать событие-поток (логика, оповещения, триггеры и т.п.) • легче масштабировать и тестировать код Если работаешь с ASP.NET Core и хочешь сделать систему событий - стоит заглянуть. Подробнее: deepumi.com/blog/building-an-event-queue-in-aspnet-core.html

💻 Асинхронная обработка данных в высоконагруженных системах 🚀 🔥 16 декабря в 20:00 мск — открытый урок в OTUS. 📌 На вебин
💻 Асинхронная обработка данных в высоконагруженных системах 🚀 🔥 16 декабря в 20:00 мск — открытый урок в OTUS. 📌 На вебинаре вы узнаете: — Как использовать асинхронную обработку данных для масштабирования сервисов — Как работают очереди сообщений, веб-сокеты и другие инструменты асинхронного взаимодействия — Как выглядит архитектура реального проекта: от веб-сервера до брокера сообщений и базы данных — Какие узкие места чаще всего встречаются в асинхронных системах и как их устранять 🎓 После занятия вы: — Разберётесь в принципах асинхронной архитектуры и её влиянии на производительность — Научитесь применять асинхронные подходы — Получите реальные примеры архитектурных решений 👉 Регистрация https://otus.pw/Ayxv/?erid=2W5zFJbb2u6 Бесплатный урок приурочен к старту курса Highload Architect, на котором вы освоите архитектуры, выдерживающие миллионы запросов в секунду, и научитесь проектировать системы без узких мест. 🚀 Реклама. ООО "ОТУС ОНЛАЙН-ОБРАЗОВАНИЕ". ИНН 9705100963.

🚀 .NET 10 - реально мощный релиз. Вот что важно знать 👇 .NET 10 и C# 14 вышли 11 ноября 2025 года. Это LTS-версия - поддерж
+7
🚀 .NET 10 - реально мощный релиз. Вот что важно знать 👇 .NET 10 и C# 14 вышли 11 ноября 2025 года. Это LTS-версия - поддержку будут выпускать до ноября 2028 года, поэтому её можно спокойно брать для продакшна. 🔥 Главное ✔ C# 14 Новый синтаксис и возможности языка: • Extension Members — расширения прямо в типах • Null-Conditional Assignment - безопасные присваивания • field keyword — точный контроль над авто-свойствами • Модификаторы у параметров лямбд • Частичные конструкторы и события ✔ File-Based Apps Теперь можно просто создать один .cs файл и запускать приложение - без .sln, без .csproj. Быстро, просто, удобно. ASP.NET Core • Валидация в Minimal APIs • JSON Patch • SSE (Server-Sent Events) • Поддержка OpenAPI 3.1 ✔ EF Core • Complex Types можно делать optional • JSON и struct внутри Complex Types • LeftJoin / RightJoin • Named Query Filters • ExecuteUpdate работает с JSON-колонками • В ExecuteUpdate теперь можно использовать обычные лямбды Полный гайд здесь: ↳ https://antondevtips.com/blog/new-features-in-dotnet-10-and-csharp-14/?utm_source=twitter&utm_medium=social&utm_campaign=04-12-2025