Делаем простой feature flags на C#!
Feature flags позволяют включать и выключать поведение без переписывания кода. Это удобно для новых экранов и постепенного выката функций.
Для примера будем хранить флаги в словаре:
Сделаем маленькую функцию проверки:
Внутри используем TryGetValue, чтобы не падать на неизвестном флаге:
Теперь флаг можно использовать в коде:
Если флага нет, функция вернёт false:
В реальном проекте словарь можно заполнять из JSON, базы или remote config. Главное, чтобы код спрашивал флаг через один понятный метод.
➡️ C# Ready | #практика
Feature flags позволяют включать и выключать поведение без переписывания кода. Это удобно для новых экранов и постепенного выката функций.
Для примера будем хранить флаги в словаре:
var flags = new Dictionary<string, bool>
{
["new-checkout"] = true,
["debug-panel"] = false
};
Сделаем маленькую функцию проверки:
static bool IsEnabled(
Dictionary<string, bool> flags,
string name)
Внутри используем TryGetValue, чтобы не падать на неизвестном флаге:
return flags.TryGetValue(name, out var enabled)
&& enabled;
Теперь флаг можно использовать в коде:
if (IsEnabled(flags, "new-checkout"))
{
ShowNewCheckout();
}
Если флага нет, функция вернёт false:
Console.WriteLine(
IsEnabled(flags, "unknown"));
В реальном проекте словарь можно заполнять из JSON, базы или remote config. Главное, чтобы код спрашивал флаг через один понятный метод.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥5❤4
Разбираем System.Threading.Channels в C#!
Channels помогают строить асинхронные очереди между producer и consumer без ручного lock вокруг коллекции. Один код пишет элементы, другой читает их по мере появления.
В этой шпоре собраны CreateUnbounded, CreateBounded, Writer, Reader, WriteAsync, ReadAllAsync и Complete.
➡️ C# Ready | #шпора
Channels помогают строить асинхронные очереди между producer и consumer без ручного lock вокруг коллекции. Один код пишет элементы, другой читает их по мере появления.
В этой шпоре собраны CreateUnbounded, CreateBounded, Writer, Reader, WriteAsync, ReadAllAsync и Complete.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7❤3👍3
Знали, что GetAsync может загрузить всё тело ответа в память ещё до начала обработки?
Для короткого JSON это обычно незаметно. С архивом или большим экспортом ситуация другая, поскольку тело ответа может занять значительную часть памяти процесса.
Обычный вызов ждёт, пока HttpClient буферизует всё содержимое:
В этом режиме обработка начинается после загрузки ответа. Для небольших данных это удобно, но для крупных файлов может создать лишний пик памяти.
Чтобы получить управление сразу после заголовков, укажи ResponseHeadersRead:
Теперь тело ещё не прочитано целиком. Сначала проверь HTTP-статус, чтобы не начать сохранять страницу с ошибкой вместо файла:
После проверки открой поток содержимого ответа:
Чтение происходит по мере обработки данных. Поток нужно использовать, пока открыт response, потому что он принадлежит этому ответу.
Например, содержимое можно копировать прямо в файловый поток:
CopyToAsync переносит данные частями, не создавая ещё один массив размером со весь файл. CancellationToken позволяет отменить и сетевой запрос, и копирование.
Если сервер сообщил размер через Content-Length, его можно проверить до сохранения:
Заголовок может отсутствовать или быть недостоверным. Для строгого ограничения размера проверяй и фактически прочитанные байты.
➡️ C# Ready | #совет
Для короткого JSON это обычно незаметно. С архивом или большим экспортом ситуация другая, поскольку тело ответа может занять значительную часть памяти процесса.
Обычный вызов ждёт, пока HttpClient буферизует всё содержимое:
using var response = await client.GetAsync(url, cancellationToken);
В этом режиме обработка начинается после загрузки ответа. Для небольших данных это удобно, но для крупных файлов может создать лишний пик памяти.
Чтобы получить управление сразу после заголовков, укажи ResponseHeadersRead:
using var response = await client.GetAsync(
url, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
Теперь тело ещё не прочитано целиком. Сначала проверь HTTP-статус, чтобы не начать сохранять страницу с ошибкой вместо файла:
response.EnsureSuccessStatusCode();
После проверки открой поток содержимого ответа:
await using var source = await response.Content.ReadAsStreamAsync(cancellationToken);
Чтение происходит по мере обработки данных. Поток нужно использовать, пока открыт response, потому что он принадлежит этому ответу.
Например, содержимое можно копировать прямо в файловый поток:
await source.CopyToAsync(destination, cancellationToken);
CopyToAsync переносит данные частями, не создавая ещё один массив размером со весь файл. CancellationToken позволяет отменить и сетевой запрос, и копирование.
Если сервер сообщил размер через Content-Length, его можно проверить до сохранения:
if (response.Content.Headers.ContentLength is long size && size > maxBytes)
throw new InvalidOperationException("File is too large");
Заголовок может отсутствовать или быть недостоверным. Для строгого ограничения размера проверяй и фактически прочитанные байты.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7👍6❤4
Собираем защиту webhook от повторной обработки!
Платёжные системы и внешние сервисы могут прислать одно и то же событие несколько раз. Наша задача обработать событие один раз и пропустить повтор.
В этой задаче:
Такой подход полезен для уведомлений, импорта заказов и любых webhook, где повторная доставка является нормальным поведением.
➡️ C# Ready | #задача
Платёжные системы и внешние сервисы могут прислать одно и то же событие несколько раз. Наша задача обработать событие один раз и пропустить повтор.
В этой задаче:
• берём idempotency key из события
• атомарно отмечаем ключ как обработанный
• пропускаем дубликаты
• отделяем проверку от бизнес-логики
Такой подход полезен для уведомлений, импорта заказов и любых webhook, где повторная доставка является нормальным поведением.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥5❤3
По данным Минфин 32% граждан покинули своё место работы поскольку уже в первый месяц смогли заработать 250 000 рублей, а через 2-3 месяца с легкостью вышли на семизначные числа.
Самое смешное, что лишь 8% россиян что-то слышали об этой профессии хотя все инструкции бесплатно лежат на канале Арбитраж Криптовалют
Там объясняют, как имея телефон и доступ в интернет заработать свои первые $3000. Причём разжёвывают так доступно, что поймёт даже ребенок. Кстати, на канале сегодня вышла новая рабочая связка!
Ссылка для входа — https://t.me/+gL6CZ_b93PBhZGM6
Please open Telegram to view this post
VIEW IN TELEGRAM
👎14
Почему для денег в C# обычно нужен decimal, а не double?
double удобен для инженерных расчётов, координат, графики и статистики. Но для денег он часто создаёт ошибки.
Причина в том, что double хранит число в двоичном формате с плавающей точкой. Не все десятичные дроби можно представить точно.
Простой пример выглядит так:
Результат может оказаться не ровно 0.3, а числом с маленьким хвостом. Для UI это иногда скрывается форматированием, но в сравнении и расчётах ошибка остаётся.
Особенно плохо сравнивать такие значения напрямую:
В финансовых сценариях обычно используют decimal:
Суффикс m важен. Без него литерал сначала будет double, и смысл decimal частично потеряется.
Для округления лучше явно указать правило:
Так код показывает, как именно округляются копейки, налоги, скидки или комиссии.
decimal медленнее и занимает больше памяти, чем double. Но для денег обычно важнее предсказуемость, чем скорость.
➡️ C# Ready | #совет
double удобен для инженерных расчётов, координат, графики и статистики. Но для денег он часто создаёт ошибки.
Причина в том, что double хранит число в двоичном формате с плавающей точкой. Не все десятичные дроби можно представить точно.
Простой пример выглядит так:
double price = 0.1 + 0.2;
Console.WriteLine(price);
Результат может оказаться не ровно 0.3, а числом с маленьким хвостом. Для UI это иногда скрывается форматированием, но в сравнении и расчётах ошибка остаётся.
Особенно плохо сравнивать такие значения напрямую:
if (price == 0.3) {
Console.WriteLine("ok");
}В финансовых сценариях обычно используют decimal:
decimal price = 0.1m + 0.2m;
Console.WriteLine(price);
Суффикс m важен. Без него литерал сначала будет double, и смысл decimal частично потеряется.
Для округления лучше явно указать правило:
decimal total = Math.Round(price, 2, MidpointRounding.AwayFromZero);
Так код показывает, как именно округляются копейки, налоги, скидки или комиссии.
decimal медленнее и занимает больше памяти, чем double. Но для денег обычно важнее предсказуемость, чем скорость.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5❤1👍1