.NET Разработчик
6.51K subscribers
427 photos
2 videos
14 files
2.04K links
Дневник сертифицированного .NET разработчика.

Для связи: @SBenzenko

Поддержать канал:
- https://boosty.to/netdeveloperdiary
- https://patreon.com/user?u=52551826
- https://pay.cloudtips.ru/p/70df3b3b
Download Telegram
День 1886. #Здоровье
10 Упражнений, Чтобы Предотвратить Боли в Спине
Давно ничего не писал на тему здоровья. Многие из нас из-за сидячей работы сталкиваются с болью в спине. И не просто периодической скованностью, а с постоянной ноющей болью, которая возникает из-за долгих сеансов программирования. Вот 10 важных упражнений, которые помогут её избежать.

1. Вращение на кресле
Что делать: сядьте прямо, поставьте ноги на пол. Возьмитесь за стол и поверните туловище влево, затем вправо. Это заставит позвоночник двигаться.
Преимущества: увеличивает подвижность позвоночника и может уменьшить скованность в течение рабочего дня. Это отличный способ поддержать кровоток, не вставая, особенно полезно во время длительных сеансов программирования.

2. Сведение лопаток
Что делать: сядьте/встаньте прямо. Представьте, что держите карандаш между лопатками и сведите их. Удерживайте 10 секунд, отпустите и повторите.
Преимущества: Упражнение нацелено непосредственно на мышцы вокруг лопаток. Улучшает осанку, уменьшает напряжение в верхней части спины и плечах, а также может помочь облегчить боль в шее за счет укрепления мышц, поддерживающих верхнюю часть позвоночника.

3. Растяжка программиста
Что делать: переплетите пальцы, вытяните их от груди, затем поднимите над головой. Слегка наклоните из стороны в сторону.
Преимущества: Эта растяжка предназначена для воздействия на области, наиболее страдающие от длительного сидения и использования клавиатуры. Вытягивание рук и наклоны из стороны в сторону усиливают растяжение верхней части тела, обеспечивая облегчение и улучшая гибкость. Увеличивает приток крови к рукам и плечам, растягивает напряженные мышцы вокруг груди и плеч и помогает предотвратить возникновение повторяющихся травм от перенапряжения.

4. Отжимания на столе стоя
Что делать: встаньте спиной к столу, положив руки на край, и медленно опустите тело, затем снова поднимитесь.
Преимущества: Использование стола для отжиманий помогает задействовать трицепсы, плечи и даже грудные мышцы. Это упражнение требует минимума движений, но развивает силу верхней части тела, которая поддерживает осанку. Укрепление этих мышц означает, что ваш позвоночник получит больше поддержки, что потенциально уменьшит боль в спине.

5. Планка для ног
Что делать: сядьте на край стула, ноги вместе, выпрямите их перед собой и задержите. Попробуйте для начала секунд 30.
Преимущества: это упражнение, представляющее собой сидячую версию планки для корпуса, позволяет сохранять прямое положение ног, активируя основные мышцы. Более сильные мышцы корпуса улучшают осанку, уменьшают нагрузку на поясницу и могут улучшить баланс и устойчивость как в кресле, так и вне его.

Окончание следует…

Источник:
https://learnhub.top/10-essential-exercises-for-programmers-to-prevent-back-pain/
👍26
День 1887. #Здоровье
10 Упражнений, Чтобы Предотвратить Боли в Спине. Окончание
Начало

6. Четвёрка сидя
Что делать: сядьте, положите одну лодыжку на противоположное колено, слегка наклонитесь вперед. Вы почувствуете легкое растяжение в бедре и пояснице.
Преимущества: это упражнение растягивает грушевидную мышцу ягодиц, частый источник седалищных болей, а также бедра и поясницу. Снижает риск боли в седалищном нерве, повышает гибкость бедра и может облегчить напряжение в пояснице, что облегчает поддержание здоровой осанки.

7. Прогулки
Что делать: каждый час совершайте 5-минутную прогулку. Будь то дома или в офисе.
Преимущества: улучшает кровообращение и предотвращает скованность, возникающую при длительном сидении. Улучшает общее состояние сердечно-сосудистой системы, повышает уровень энергии и даже может повысить креативность и способность решать проблемы, давая вашему мозгу отдохнуть от экрана.

8. Настенный ангел
Что делать: встаньте спиной к стене, ноги слегка вперед. Двигайте руками вверх и вниз, как будто делаете снежного ангела.
Преимущества: помогает исправить осанку, выравнивая позвоночник и плечи, увеличивает подвижность плеч и уменьшает боли в верхней части спины, вызванные сутулостью.

9. Кошка-корова
Что делать: встаньте на четвереньки. Выгните спину вверх, прижав подбородок к груди (кошка), затем опустите спину вниз, задрав голову вверх (корова).
Преимущества: мягкое плавное движение, которое растягивает позвоночник и помогает придать гибкость всей спине и снять напряжение в пояснице. Это также отличное средство от стресса и помогает сосредоточиться.

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

Помните, постоянность является ключевым моментом. Включение этих упражнений в свой распорядок дня может значительно снизить риск развития болей в спине. Кроме того, короткие перерывы для физической активности могут повысить вашу продуктивность и творческий потенциал. Уделяйте своей спине такую же заботу и внимание, как и своему коду, и оставайтесь здоровыми и продуктивными!

Источник: https://learnhub.top/10-essential-exercises-for-programmers-to-prevent-back-pain/
👍10
День 1888. #ProjectManagement
Что Такое SLI, SLO и SLA
При проектировании архитектуры ПО мы должны учитывать как функциональные, так и нефункциональные требования. Сегодня разберём SLO, SLA и SLI и как они влияют на жизненный цикл ПО.

1. Индикатор уровня обслуживания (Service Level Indicator - SLI)
Измеримая мера некоторого аспекта уровня предоставляемого обслуживания: процент времени безотказной работы, время ответа или частота сообщений об ошибках. SLI используются для объективного измерения производительности сервиса и для проверки SLO.

Как отслеживать?
- Тщательно определите проверяемые метрики. Например «ошибки HTTP» - недостаточно чётко. Какие именно? 404, 401 и 500 — обозначают ошибки, но их появление может как указывать, так и не указывать на ошибки в системе.
- Определите функции для проверки качества релизов, чтобы гарантировать, что новый релиз не ухудшит существующие значения SLI.

2. Целевой уровень обслуживания (Service Level Objective - SLO)
Целевой уровень обслуживания между поставщиком услуг и конечным пользователем, который измеряется конкретными показателями. Если SLI —фактическое значение измерения, SLO — конечная цель, которую необходимо достичь для этого SLI. SLO - желаемая цель для некоторых показателей (обычно производительности и надёжности), которых стремится достичь сервис. Вы можете указать значение SLO для каждой метрики, которая важна для вас и ваших клиентов. Например:
- 99% запросов к веб-сервису должны иметь задержку менее 300 мс;
- 99,9% запросов к определённой конечной точке должны иметь задержку менее 100 мс;
- 99,9% запросов должны возвращать успешный код состояния.
SLO являются конкретными, подробными и измеримыми. Например, заявление: «Запросы, как правило, должны быть быстрыми» - слишком расплывчато, и его невозможно измерить.

Как отслеживать?
- Создайте информационную панель для измерения каждого из определённых вами SLO.
- Отправляйте оповещения, если значение достигает порога.
- Спроектируйте архитектуру с учётом значений SLO: например, если необходимо обеспечить низкую задержку для запросов, можно спроектировать асинхронную связь между сервисами или решить развернуть приложение близко к местоположению пользователей.

3. Соглашение об уровне обслуживания (Service Level Agreement - SLA)
Официальное соглашение между поставщиком услуг и клиентом. В отличие от SLO, SLA имеют юридическую силу и предусматривают последствия несоблюдения. Если продукт не соответствует SLA, это может вести к штрафам, неустойкам и т.п. Примером SLA является скорость реагирования техподдержки, например, закрывать открытую клиентом заявку в течение 24 часов.

Взаимодействие между SLO, SLA и SLI существенно влияет на решения по архитектуре ПО:
- SLO и SLI помогают архитекторам определить показатели надёжности и производительности, которым должна соответствовать система. Это влияет на выбор технологий и шаблонов, позволяющих достичь этих показателей. Микросервис или монолит? С# или Rust? Локально или в облаке?
- Для соблюдения требований SLO системе может потребоваться обрабатывать большое количество запросов в секунду, что требует масштабируемых архитектур, таких как микросервисы или бессерверные вычисления.
- Необходимость соблюдения SLA может привести к внедрению механизмов резервирования и аварийного переключения для обеспечения высокой доступности и минимизации времени простоя.
- SLI требуют надёжных систем мониторинга и оповещения для отслеживания производительности услуги в режиме реального времени и уведомления, когда SLO подвергаются риску нарушения.
- Необходимость удовлетворять SLO может влиять на распределение ресурсов, что приводит к принятию решений о балансировке нагрузки, сегментировании базы данных или использовании сетей доставки контента (CDN).
- Штрафы, связанные с SLA, могут повлиять на стоимость, побуждая архитектуру быть более экономичной, при этом соответствуя уровням обслуживания.

Источник: https://www.code4it.dev/architecture-notes/sli-vs-slo-vs-sla/
👍13
День 1889. #ЗаметкиНаПолях
Проверка Схемы Json в .NET
Часто бывает полезно проверять документы JSON на соответствие схеме. Схема JSON — это словарь, который можно использовать для аннотирования и проверки документов JSON. Например, вы можете проверить документ JSON, полученный от REST API, или файл конфигурации, написанный пользователем. Сегодня посмотрим, как проверить данные JSON на соответствие схеме в .NET.

Совет. В PowerShell, вы можете использовать командлет Test-Json для проверки данных JSON на соответствие схеме JSON.

.NET не поддерживает проверку схемы JSON «из коробки». Однако существует несколько сторонних библиотек, которые можно использовать для проверки данных JSON на соответствие схеме. Здесь мы используем библиотеку JsonSchema.Net https://www.nuget.org/packages/JsonSchema.Net.

Создадим проект:
dotnet new console
dotnet add package JsonSchema.Net

Следующий код показывает, как проверить данные JSON на соответствие схеме:
using System.Text.Json.Nodes;
using Json.Schema;

//пример схемы
var schema = """
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/product.schema.json",
"title": "Product",
"description": "A product from Acme's catalog",
"type": "object",
"properties": {
"productName": {
"description": "Name of the product",
"type": "string"
},
"price": {
"description": "The price of the product",
"type": "number",
"exclusiveMinimum": 0
}
},
"required": [ "productName", "price" ]
}
""";

// полученные данные
var json = """
{
"productName": "test",
"price": -1
}
""";

// Проверка
var jsonSchema = JsonSchema.FromText(schema);
var result = jsonSchema
.Evaluate(JsonNode.Parse(json));

if (!result.IsValid)
{
Console.WriteLine("Invalid document");
if (result.HasErrors)
{
foreach (var error in result.Errors)
Console.WriteLine(error.Key + ": " + error.Value);
}
}

Источник:
https://www.meziantou.net/json-schema-validation-in-dotnet.htm
👍13
День 1890. #ЧтоНовенького
В C# 13 Разрешат ref и unsafe в Итераторах и Асинхронном Коде

Сейчас вы не можете написать так:
async Task MyMethodAsync()
{
await AnAsyncMethod();
ref int x = ref GetRef();
DoSomething(ref x);
await AnohterAsnycMethod();
}

Проблема совместного использования await и ref заключается в том, что компилятор не может гарантировать, что ссылка по-прежнему будет действительна после await. Но в приведённом выше случае это не должно быть проблемой, поскольку x используется только между двумя вызовами await, где ссылка всё ещё действительна.

То же самое относится и к ссылочным структурам, таким как Span<T> или ReadOnlySpan<T>. Вы не можете использовать их в итераторах (yield) или асинхронных методах. Предложение позволит писать так:
async Task MyMethodAsync()
{
var result = await AnAsyncMethod();
var span = result.AsSpan();
DoSomething(span);
await AnohterAsnycMethod();
}


Подробности предложения здесь.

Источник: https://steven-giesel.com/blogPost/0d4216e5-4445-48c4-8d9c-3ff5aa1bfdc3/c-13-allow-ref-and-unsafe-in-iterators-and-async
👍8
День 1891. #ЗаметкиНаПолях
Используем localStorage в Современных Приложениях. Начало

API localStorage позволяет разработчикам хранить пары ключ-значение в браузере пользователя. Сегодня рассмотрим различные аспекты API localStorage, преимущества, ограничения и альтернативные варианты.

Что это?
API localStorage — встроенная функция браузеров, позволяющая веб-разработчикам постоянно хранить небольшие объёмы данных в формате «ключ-значение» на устройстве пользователя. Данные остаются доступными даже после того, как пользователь закрывает браузер или уходит со страницы. Это удобный способ поддерживать состояние и сохранять пользовательские настройки, не полагаясь на хранилище на стороне сервера.
// Сохранение
localStorage.setItem('username', 'john_doe');

// Извлечение
let user = localStorage.getItem('username');

// Удаление
localStorage.removeItem('username');

// Очистка
localStorage.clear();

Хранение сложных данных возможно с помощью сериализации JSON (JSON.stringify и JSON.parse):
let user = {
name: 'Alice',
age: 42,
email: '[email protected]'
};

localStorage.setItem('user',
JSON.stringify(user));

let storedUser =
JSON.parse(localStorage.getItem('user'));


Ограничения
1. Неасинхронный API. Любые операции в localStorage потенциально могут заблокировать основной поток.
2. Ограниченная структура данных. Простое хранилище ключ-значение делает localStorage непригодным для хранения сложных структур данных или управления связями между элементами данных.
3. Накладные расходы. Хранение JSON требует сериализации, потенциально замедляя операции до 10 раз.
4. Отсутствие индексации. Нет возможности индексирования, что затрудняет эффективный поиск или перебор данных на основе определённых критериев.
5. Блокировка вкладок. Операции localStorage на одной вкладке могут повлиять на производительность других вкладок, монополизируя ресурсы ЦП.
6. Ограничение хранилища. Обычно около 5 МБ для каждого источника localStorage.

Причины использовать
API localStorage в JavaScript работает на удивление быстро по сравнению с альтернативными решениями. Он превосходно справляется с хранением небольших данных. Доступ к данным localStorage и их изменение требуют минимальных затрат.

Когда не использовать
1. Данные извлекаются через запросы по критериям.
localStorage не предоставляет таких возможностей. Сложный поиск данных может привести к неэффективному коду и снижению производительности.
2. Большие документы JSON.
Важно оценить размер данных и рассмотреть более надёжные решения для обработки значительных наборов данных.
3. Множество операций чтения/записи.
Чрезмерное количество операций чтения и записи в localStorage может привести к снижению производительности.
4. Нет необходимости в постоянном хранении данных.
Если приложению не нужно хранить данные между сеансами, лучше использовать структуры данных в памяти, такие как Map или Set. Они обеспечивают скорость и эффективность обработки временных данных.

Окончание следует…

Источник:
https://rxdb.info/articles/localstorage.html
👍13
День 1892. #ЗаметкиНаПолях
Используем localStorage в Современных Приложениях. Окончание

Начало

Что использовать вместо localStorage в JavaScript?

IndexedDB
IndexedDB предназначена для хранения не только пар ключ-значение, но и документов JSON. В отличие от localStorage, может обрабатывать значительно большие наборы данных, поддерживает индексирование, упрощает выполнение запросов, делая возможными запросы по диапазонам. Однако сложные запросы могут создавать проблемы. Существуют библиотеки-оболочки, такие как RxDB или Dexie.js. Они дополняют IndexedDB такими функциями, как сложные запросы и наблюдаемость, повышая удобство использования для современных приложений.

API файловой системы (OPFS)
Обеспечивает прямой доступ к изолированной под каждый источник файловой системе, которая высоко оптимизирована для производительности и предлагает доступ для записи. Однако работа с API OPFS может быть сложной, и она доступна только внутри WebWorker. Чтобы упростить его использование и расширить его возможности, есть библиотеки-оболочки, такие как OPFS RxStorage, которая создает комплексную базу данных поверх API OPFS.

Куки
Куки когда-то были основным методом хранения данных на стороне клиента, но потеряли популярность в современной веб-разработке из-за своих ограничений. Они могут хранить данные, но работают примерно в 100 раз медленнее, чем API localStorage. Кроме того, куки включаются в заголовок HTTP, что может повлиять на производительность сети. Куки не рекомендуются для хранения данных в современных веб-приложениях.

WebSQL
WebSQL предлагает SQL-интерфейс для хранения данных на стороне клиента, но является устаревшей технологией, и её следует избегать. Этот API постепенно выводится из современных браузеров.

sessionStorage
Этот механизм хранения сохраняет данные только на время работы вкладки или сеанса браузера. Он выдерживает перезагрузку и восстановление страниц. Но важно отметить, что sessionStorage ограничен по объёму и может не подходить для всех случаев использования.

AsyncStorage для React Native
Подходящее решение, похожее на localStorage, но с поддержкой асинхронного кода. Удобная альтернатива для сохранения данных в приложениях React Native.

node-localstorage для Node.js
Нативный localStorage не определён в Node.js (Next.js). npm-пакет node-localstorage устраняет этот пробел.

localStorage в расширениях браузера
Расширения для Chrome и Firefox поддерживают API localStorage, но не рекомендуется использовать его в этом контексте. Браузер очищает данные во многих сценариях, например, когда пользователи очищают историю просмотров. Вместо этого для расширений браузера следует использовать Extension Storage API. Он работает асинхронно, обеспечивает автоматическую синхронизацию для репликации данных между всеми экземплярами браузера, где пользователь авторизован, а также способен хранить JSON-объекты, вместо простых строк.

Итого
Простота и скорость localstorage делают его отличным выбором для небольших данных. Но по мере роста сложности приложений разработчики должны тщательно оценивать потребности в хранилище. Для сценариев, требующих расширенных запросов, сложных структур данных или операций с большими объёмами, альтернативы, такие как IndexedDB или API для конкретной платформы, предлагают более надёжные решения.

Источник: https://rxdb.info/articles/localstorage.html
👍5
День 1893. #УрокиРазработки
Уроки 50 Лет Разработки ПО


Урок 3. Интересы всех сторон пересекаются в требованиях
Успех проекта – это удовлетворение всех требований и соблюдение всех ограничений, определяющих ожидания заинтересованных сторон. Команда разработчиков должна определить заинтересованные стороны и порядок взаимодействия с ними.
Заинтересованная сторона — это любое лицо или группа людей, активно участвующих в проекте, затрагиваемых им или способных влиять на его продвижение. Обычно это команда разработки, клиенты, прямые пользователи, косвенные пользователи, регулирующие органы и т.п.

Анализ
Команда проекта должна заранее определить потенциальные группы заинтересованных сторон. Список может получиться длинным и потребовать усилий. Но это лучше, чем игнорировать критически настроенное сообщество и вносить коррективы на поздних стадиях проекта.

Чтобы упростить исследование требований, разделите пользователей на группы с разными наборами потребностей. Пользователи могут быть даже не людьми, а аппаратными устройствами или другим ПО. Нужно определить людей, которые могут предоставить требования от имени этих компонентов.
Могут быть и непрямые пользователи продукта. Например, получатели годовых отчётов компании не взаимодействуют с ПО напрямую, но они основные заинтересованные стороны. Необходимо также определить классы нежелательных пользователей, которые не должны иметь возможности пользоваться системой. Например, хакеры не являются заинтересованной стороной (не определяют требования или ограничения), но нужно предвидеть и пресекать их злые намерения.

Для каждой группы заинтересованных сторон, опишите:
1. Кто они? Чтобы все участники проекта понимали, кто это.
2. Насколько они заинтересованы? Как сильно результат проекта повлияет на группу и как их желание участвовать в проекте. Их ожидания, интересы, опасения и ограничения.
3. Какое влияние на проект они имеют? Какие решения могут и не могут принимать. Кто влияет больше всего? Особое внимание группам, которые проявляют наибольший интерес и оказывают наибольшее влияние.
4. С кем лучше говорить? Представители каждой группы, с которыми нужно работать. Они должны быть авторитетными источниками информации.
5. Где они? Проще получить информацию, если есть прямой доступ к представителям группы. Либо продумайте процесс коммуникации.
6. Что нам нужно от них? Информация, решения и данные, которые понадобятся получить от каждой группы. Некоторые группы будут накладывать ограничения на проект, например:
- финансовые, временные и ресурсные;
- применимые политики, нормы и стандарты (бизнес-правила);
- совместимость с другими продуктами, системами или интерфейсами;
- юридические или договорные;
- требования к сертификации;
- ограничения возможностей продукта (что не должно включаться в продукт).
7. Что им нужно от нас? Одних нужно проинформировать о проблемах, другим может понадобиться пересмотреть требования.
8. Как и когда с ними взаимодействовать?
9. Какие стороны наиболее важны при разрешении конфликтов? При разрешении противоречий и принятии важных решений оцените, какой результат больше всего соответствует целям проекта. Проанализируйте влияние и интересы сторон, не ждите, пока назреет первый конфликт.

Мы все на одной стороне
Определите лиц, принимающих решения. Иногда это один человек (спонсор или владелец продукта). Чаще придётся определять правильные группы людей для принятия решений из разных областей. Групповые решения требуют больше времени, но лучше отражают все интересы, соответствующие целям проекта. Цели, ограничения и другие бизнес-требования обычно оформляются в виде заявления о видении.

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

Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 2.
👍3
День 1894. #Карьера #Продуктивность
Начинайте Работу Через Минуту После Пробуждения

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

Однако наиболее продуктивные люди в мире ничего такого не делают. Они просто просыпаются и начинают работать. Поначалу это может показаться странным и трудным – работать не до конца проснувшись. Но на самом деле это самое продуктивное время дня. Психолог Михай Чиксентмихайи в 1970х назвал это склонностью к потоку (flow proneness) – это настрой организма к работе в потоке.

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

Но дело в том, что, когда вы просыпаетесь, ваша склонность к потоку наиболее высока по естественным причинам:
1) Низкая когнитивная нагрузка. Вы только проснулись, мозг ещё не нагружен новой информацией.
2) Активность мозга после пробуждения близка к состоянию потока. После сна он готов воспринимать новую информацию.
Поэтому занимать это время утренней рутиной, которая призвана помочь войти в поток позже, не имеет смысла.

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

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

Проснитесь, и сразу приступайте к самой важной работе. Не через час, не через 10-15 минут, а в течение 60-90 секунд, пока вы ещё наполовину спите. В течение нескольких минут вы полностью проснётесь и будете работать в состоянии потока. Поработайте так 1-3 часа. После этого займитесь тем, что обычно поднимает вам настроение с утра и позволяет подготовиться к рабочему дню: чашка кофе, контрастный душ, йога, прогулка. Воспринимайте это как утреннюю рутину наоборот: сначала поработать, потом восстановиться. Так мы используем самое продуктивное время после пробуждения, данное нам природой, и восстанавливаемся после этого, чтобы зарядиться энергией на оставшийся день.

И ещё два совета.
1) Подготовьтесь заранее. Составьте подробный список дел накануне вечером. Так, чтобы с утра не думать, что надо делать, а сразу приступать к делу.
2) Выделите достаточно времени. 1-3 часа на активную работу в состоянии потока, не отвлекаясь.

Попробуйте начать завтра. Сегодня составьте список самых важных день на завтра, а как проснётесь (в идеале, в течение 60-90 секунд), принимайтесь за работу. После этого позвольте себе восстановиться и перезагрузиться, чтобы настроиться на продуктивную работу в оставшееся время дня.

Источник: https://youtu.be/XJOsPyyYork
👍25
День 1895.
Сопоставление с Образцом и Компилятор Могут Удивлять
Сопоставление с образцом — мощная функция C#. Она позволяет сопоставлять значение с шаблоном и извлекать информацию из значения. Компилятор творит за вас волшебство, но иногда этим и поражает.

Вот такой фрагмент кода рассылки писем:
Console.WriteLine(
GetHashCode(new PostCard { Subject = "Test" }));

static int GetHashCode(Document doc)
{
return doc switch
{
PostCard { Subject: { } s, Text: { } t }
=> HashCode.Combine(s, t),
Mail { Subject: { } s }
=> s.GetHashCode(),
_ => 0,
};
}

public class Document;
public class Mail : Document
{
public string? Subject { get; set; }
}
public class PostCard : Mail
{
public string? Text { get; set; }
}

Функция GetHashCode принимает Document и возвращает хэш-код. Она использует сопоставление с образцом для сопоставления типа и получения хэш-кода. Интересная часть PostCard { Subject: { } s, Text: { } t } по сути гарантирует, что Subject и Text не null. Второе условие проверяет только базовый тип (мы идём от более конкретного к более общему). В чём тут сюрприз? В том, что код выдаёт предупреждение:
Program.cs(11,9): Warning CS8602 : Dereference of a possibly null reference (Разыменование возможно нулевой ссылки).
Вот в этом месте
Mail { Subject: { } s }
=> s.GetHashCode(),

Учитывая, что мы явно проверяем, что Subject не null, почему компилятор на это жалуется? Для этого нам нужно взглянуть на сгенерированный компилятором код:
internal static GetHashCode(Document doc)
{
PostCard postCard = doc as PostCard;
string subject2;
if (postCard != null)
{
string subject = postCard.Subject;
if (subject != null)
{
string text = postCard.Text;
if (text == null)
{
Mail mail = (Mail)doc;
subject2 = mail.Subject;
goto IL_0057;
}
return HashCode.Combine(subject, text);
}
}
else
{
Mail mail = doc as Mail;
if (mail != null)
{
subject2 = mail.Subject;
if (subject2 != null)
{
goto IL_0057;
}
}
}
return 0;
IL_0057:
return subject2.GetHashCode();
}

Кажется, статический анализатор видит проблему в операторе goto в ветке PostCard. Заметьте, что subject проверяется на null, a subject2 нет.

Так что, если в вашем коде есть именно такой шаблон, возможно, вам стоит об этом знать. Оговорюсь, что случаи, когда этот код фактически выдаст исключение NullReferenceException – крайне редкие. Вот такой вымышленный пример:
public class Mail : Document
{
private string? subject;
public string? Subject
{
get
{
Console.WriteLine("Вызвали get");
var r = subject;
subject = null;
return r;
}
set => subject= value;
}
}

В этом случае при вызове
Console.WriteLine(
GetHashCode(new PostCard { Subject = "Test" }));

аксессор get свойства Mail.Subject будет вызван дважды:
1) в строке string subject = postCard.Subject;
2) в строке subject2 = mail.Subject;
И из-за нашего специального кода get выше, во втором случае get выдаст null, поэтому return subject2.GetHashCode(); выбросит NullReferenceException. Выполнив этот код, вы увидите «Вызвали get» в консоли дважды перед исключением.

Источник: https://steven-giesel.com/blogPost/9892bd03-96bf-4ab0-aacc-973a99d5f5e0/pattern-matching-and-the-compiler-can-be-surprising
👍10
День 1896. #Оффтоп #Безопасность
Бэкдор в SSH Linux

«Linux безопасен», - говорили они. «В Linux нет вирусов», - говорили они.

Зато туда едва не проник бэкдор, который мог позволить его автору получать root доступ к любой (!!!) машине под управлением Linux и в которой была установлена нужная версия библиотеки XZ Utils. Причём сделал это один из её главных контрибуторов и довольно хитро - в make-файле (которые обычно никто досконально не проверяет). Бэкдор активировался при сборке проекта. Насколько я понял, достаточно было добавить малозаметную точку в файл в очередном релизе, чтобы сборка «выбрасывала ошибку» при поиске одной из нужных библиотек, и вместо неё использовала «стандартную» с уязвимостью. После этого оставалось только ждать, пока все серверы обновят версию библиотеки и…

По иронии судьбы обнаружил это парень из Microsoft. Он заметил, что его входы в систему стали занимать дольше обычного (2,5 секунды против 2х раньше), и стал копать. Из-за этой счастливой случайности уязвимость не успела распространиться далее нескольких превью версий.

Национальная база данных уязвимостей США присвоила этой уязвимости критичность 10 из 10.

Больше подробностей об этом, а также чем процесс релиза кода в Microsoft отличается от процесса в «диком опенсорсе» смотрите в видео Dave’s Garage.
👍27
День 1897. #ЗаметкиНаПолях
5 правил для DTO

DTO — это объект передачи данных (Data Transfer Object). Его задача — передавать данные, и его можно использовать как для отправки данных, так и для их получения.

Часто передаваемые данные используют разные типы (возможно, даже разные языки программирования и стеки технологий) на каждом конце передачи. Единственное, на что вы можете рассчитывать при передаче – это данные и ничего больше. Они должны легко сериализовываться и десериализовываться в JSON, XML и т.п. Поведение сложно будет десериализовать на принимающей стороне. Отсюда первое правило для DTO.

Правило 1. DTO должны содержать только данные. Никакой логики и поведения.

С DTO должно быть очень легко работать, а также создавать их. Они не получают выгоды от инкапсуляции, и, как правило, им также следует избегать использования наследования (сокрытие вещей - это не то, что мы хотим с помощью DTO, а повторное использование типов в этом случае переоценено). В качестве DTO в .NET часто используют записи.

Правило 2. DTO не обеспечивают инкапсуляцию. Им не нужны приватные/защищённые члены.

Даже несмотря на то, что DTO не нуждаются в инкапсуляции, обычно предпочитают использовать свойства C#, а не поля. По умолчанию сериализаторы и другие функции языка работают со свойствами, а не с полями (хотя вы можете это настроить).

Правило 3. DTO должны использовать свойства (а не поля).

Очевидным соглашением об именах является простое добавление «DTO» (или «Dto») в конец имени объекта. Хотя это работает и подходит для самого простого представления, во многих случаях вам следует использовать более описательное имя.

Многие распространённые типы, используемые в современных приложениях .NET, могут (и обычно должны) создаваться как DTO. К ним относятся объекты запросов и ответов API, команды и запросы в CQ(R)S, события и многое другое. В таких случаях добавьте к типу более конкретное имя (например, «CreateUserRequest» вместо просто «UserDTO»).

Правило 4. DTO следует использовать суффикс «-DTO» только в крайнем случае. Предпочитайте более описательные имена.

Некоторые объекты в приложении должны быть DTO и называться в соответствии с их конкретным использованием, а не «FooDTO».

Правило 5. Следующие модели должны быть спроектированы как DTO:
- типы запросов/ответов API,
- модели представления в MVC,
- объекты результатов запроса к БД,
- сообщения (команды, события и запросы).


Для валидации свойств DTO вы можете использовать аннотации данных, IValidatableObject, FluentValidation или ключевое слово required.

Источник: https://ardalis.com/5-rules-dtos/

См. также:
- В чём разница между DTO и POCO?
- Ваш API и Модели Представления не Должны Использовать Модели Домена
👍25
День 1898. #ЗаметкиНаПолях
Горизонтальное Масштабирование API с Помощью YARP.
Современные веб-приложения должны обслуживать растущее число пользователей и справляться с резкими скачками трафика. Балансировка нагрузки — ключевой метод решения этих проблем и улучшения масштабируемости приложения.

Существует два основных подхода:
1. Вертикальное масштабирование – обновление железа серверов: больше ядер ЦП, больше памяти, более быстрое хранилище.
2. Горизонтальное масштабирование - добавление дополнительных серверов и разумное распределение нагрузки между ними.

Добавляем обратный прокси
YARP — это высокопроизводительная библиотека обратного прокси от Microsoft. Обратный прокси находится перед вашими серверами и управляет трафиком между ними (см. картинку ниже). YARP позволяет выполнять задачи маршрутизации и преобразования входящих запросов до того, как они достигнут ваших внутренних серверов. Входящие запросы к API сначала попадают в YARP, который распределяет трафик на серверы приложений на основе стратегии балансировки нагрузки. В примере на картинке одна база данных, обслуживающая несколько экземпляров приложения.

1. Сначала установим NuGet:
Install-Package Yarp.ReverseProxy

2. Настроим необходимые сервисы и промежуточное ПО:
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddReverseProxy()
.LoadFromConfig(
builder.Configuration
.GetSection("ReverseProxy"));

var app = builder.Build();

app.MapReverseProxy();

app.Run();

3. Добавим конфигурацию в appsettings.json. YARP использует маршруты (Routes) для представления входящих запросов к обратному прокси и кластеры (Clusters) для определения нижестоящих сервисов. Шаблон {**catch-all} позволяет маршрутизировать все входящие запросы.

Существуют различные стратегии балансировки нагрузки:
1. PowerOfTwoChoices - выбирает два случайных пункта назначения и из них тот, у которого меньше назначенных запросов.
2. FirstAlphabetical - выбирает первый доступный целевой сервер в алфавитном порядке.
3. LeastRequests - отправляет запросы на серверы с наименьшим количеством назначенных запросов.
4. RoundRobin - равномерно распределяет запросы по внутренним серверам.
5. Random - сервер выбирается случайным образом для каждого запроса.
Стратегию балансировки нагрузки можно настроить с помощью свойства LoadBalancingPolicy в кластере.
{
"ReverseProxy": {
"Routes": {
"api-route": {
"ClusterId": "api-cluster",
"Match": {
"Path": "{**catch-all}"
},
"Transforms": [{ "PathPattern": "{**catch-all}" }]
}
},
"Clusters": {
"api-cluster": {
"LoadBalancingPolicy": "RoundRobin",
"Destinations": {
"destination1": {
"Address": "https://api-1:8080"
},
"destination2": {
"Address": "https://api-2:8080"
},

}
}
}
}
}

Итого
YARP — мощный и удобный обратный прокси-сервер для приложений .NET. Однако очень сложные, крупномасштабные распределённые системы могут выиграть от специализированных автономных решений по балансировке нагрузки, которые предлагают более детальный контроль и сложные функции.

См. также Создаём API-Шлюз для Микросервисов с Помощью YARP.

Исходный код с тестами производительности тут.

Источник: https://www.milanjovanovic.tech/blog/horizontally-scaling-aspnetcore-apis-with-yarp-load-balancing
👍12
День 1899. #УрокиРазработки
Уроки 50 Лет Разработки ПО


Урок 4. В требованиях главное особенности использования, а затем — функциональность
В индустрии ПО существует убеждение, что от 50 до 80% возможностей ПО используются редко или не используются никогда.

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

Нужно смещать акцент с функциональности на особенности использования, с решения на потребность. Это поможет быстрее понять контекст и цели пользователя и точнее определить, какими возможностями должно обладать решение, для кого оно, как и когда будет использоваться. Учитывая и технические возможности, и особенности использования, можно определить и функциональные требования. Но фокус на особенностях использования позволит гарантировать, что в продукт будут добавлены те функции, которые действительно необходимы пользователям для выполнения их задач.

Меняется суть вопросов во время сбора информации. Вместо «Что вы хотите?» или «Что должна делать система?» можно спросить: «Как предполагается использовать систему?» Редкие пользователи запускают приложение ради определённой функции; подавляющее большинство стремится достичь конкретной цели. Я открываю приложение, имея определённое намерение, и выполняю последовательность шагов, вызывая функции, необходимые для решения задачи. Если всё хорошо, то я успешно решаю свою задачу и закрываю приложение.

Преимущества вариантов использования
1. Помогают пользователям задуматься о своих потребностях. Им сложно правильно сформулировать перечень функций продукта, но они легко расскажут о сценариях использования из своей жизни. По этим описаниям можно определить, какие функции должно предоставить приложение, чтобы пользователи могли решать поставленные задачи. Также учитывайте, какие ошибки могут возникнуть и как система должна их обрабатывать.
2. Помогают расставить приоритеты. Одни варианты использования будут более важными, поэтому должны быть реализованы в первую очередь. Наивысший приоритет имеет нормальный сценарий вместе с возможными нештатными ситуациями. Альтернативные сценарии имеют более низкий приоритет, их реализацию часто откладывают или отменяют вообще.
3. Более продуктивное взаимодействие с пользователем и более полное представление об ограничениях реализации, которое труднее получить, при разговоре о функциональности продукта.

Проблема пользовательских историй
Пользовательская история (user story) описывает функциональность, которая будет полезна как пользователю, так и покупателю системы. Они обычно записываются с использованием простого шаблона:
Как <тип пользователя>, я хочу <описание решаемой задачи>, чтобы я мог <достижение некой цели>.

или
Как <тип пользователя>, я хочу достичь <некая цель>, чтобы <некий результат>.


Одна из проблем пользовательских историй в том, что они не имеют внутренней организационной схемы. Множество историй, даже записанных по шаблону, мало чем отличается от вопроса: «Чего вы хотите?» Вы получаете много кусочков важной информации, перемешанных с посторонними сведениями. Требуется, чтобы кто-то отсортировал их и выявил темы, связанные с пользовательскими задачами.

Альтернативой является шаблон истории работы (job story), который ёмко и структурированно описывает потребность:
Когда <ситуация>, я хочу выполнить <задачу>, чтобы я достичь <желаемый результат>.


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

Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 2.
👍11
День 1900. #ЗаметкиНаПолях
Добавляем Деконструктор в Сторонние Типы
Деконструктор — это функция языка C#, позволяющая определить метод, который будет вызываться при разделении объекта на компоненты. Это легко реализовать для ваших собственных типов, но можно добавить и для сторонних типов.

Например:
public class Point
{
public int X { get; }
public int Y { get; }

public Point(int x, int y)
{
X = x;
Y = y;
}

public void Deconstruct(out int x, out int y)
{
x = X;
y = Y;
}
}

// Использование
var point = new Point(3, 4);
var (x, y) = point;

Красиво и просто, но ваш класс должен определить метод Deconstruct. Что делать, если вы хотите деконструировать сторонний тип, который вы не можете изменить? Компилятор будет искать метод с сигнатурой Deconstruct в типе, который вы пытаетесь деконструировать, но он также будет искать и метод расширения с той же сигнатурой. Т.е. можно определить деконструктор для стороннего типа, определив метод расширения с той же сигнатурой:
public static class Extensions
{
public static void Deconstruct(
this Uri uri,
out string scheme,
out string host,
out string path,
out string query,
out string fragment)
{
scheme = uri.Scheme;
host = uri.Host;
path = uri.AbsolutePath;
query = uri.Query;
fragment = uri.Fragment;
}
}

// Использование
var url =
"https://www.google.com/search?q=dotnet#ip=1";
var (scheme, host, path, query, fragment)
= new Uri(url);

Console.WriteLine($"Scheme: {scheme}"); // https
Console.WriteLine($"Host: {host}"); // google.com
Console.WriteLine($"Path: {path}"); // /search
Console.WriteLine($"Query: {query}"); // ?q=dotnet
Console.WriteLine($"Fragment: {fragment}"); // #ip=1

Это довольно нишевая функция, и она скорее про удобство, чем про необходимость. Однако если у вас есть фиксированный набор необходимых свойств типа, это может быть очень кратким способом их получения.

Источник: https://steven-giesel.com/blogPost/0775d3d3-8f90-4546-95d8-71a6b1e7b0e8/equip-3rd-party-types-with-a-deconstructor
👍25
Вы разрабатываете веб-API ASP.NET Core, который должен поддерживать форматирование ответов в как в JSON, так и в XML. По умолчанию поддерживается только форматирование в JSON. Как добавить форматирование в XML?
#Quiz #ASPNET
Anonymous Quiz
15%
Добавить опцию AcceptXml = true в промежуточное ПО AddControllers в Startup.ConfigureServices
13%
Добавить NuGet пакет Microsoft.Extensions.XmlFormatters
28%
Добавить UseXmlSerializer в Startup.Configure
44%
Добавить AddXmlSerializerFormatters в Startup.ConfigureServices
👍18👎18
День 1901. #ЧтоНовенького #Csharp13
Простая Обработка Асинхронных Задач по Мере их Завершения в .NET 9

Допустим, вам нужно обрабатывать результаты нескольких асинхронных задач по мере их завершения. Мы можем предположить, что это обращения к API, БД, файловой системе, долгие вычисления и т.п.

Например, симулируем некоторую задачу Calculate, которая выдаёт результат через случайное (от 0,5 до 5 секунд) время:
async Task<int> Calculate(int order)
{
var wait = Random.Shared.Next(500, 5000);
await Task.Delay(wait);
return order;
}

И пусть у нас есть несколько таких задач:
var tasks = Enumerable.Range(1,10)
.Select(Calculate).ToList();

Если мы будем ожидать окончания всех задач, и выводить их результаты, то получим результаты в порядке очереди (от 1 до 10) вне зависимости от того, когда завершилась каждая задача, потому что мы сначала ждём завершения всех:
var results = await Task.WhenAll(tasks);
foreach (var r in results)
Console.WriteLine(r);

Более эффективно было бы ожидать завершения каждой задачи и обрабатывать её результат сразу. До сих пор существовал некоторый обходной путь, позволяющий это сделать. Примерно так:
while (tasks.Any())
{
var finished = await Task.WhenAny(tasks);
tasks.Remove(finished);
Console.WriteLine(await finished);
}

Это работает, но логика не совсем очевидная. Кроме того, должна быть доступна операция удаления выполненной задачи (т.е. должен быть список задач).

В .NET 9 появился новый метод, позволяющий упростить эту логику, Tasks.WhenEach, который выдаёт IAsyncEnumerable. Тогда код выше сокращается до:
await foreach (var finished 
in Task.WhenEach(tasks))
{
Console.WriteLine(await finished);
}

Теперь вы избавлены от необходимости иметь список задач в List’е (метод принимает Task<T>[], ReadOnlySpan<Task<T>>, IEnumerable<Task<T>>. Кроме того, он использует новые возможности ключевого слова params.

Аналогичная функциональность уже существует в библиотеке AsyncEx Стивена Клири. Там это метод OrderByCompletion. Поэтому можно эмулировать метод WhenEach так:
async IAsyncEnumerable<T> WhenEach(Task<T>[] tasks) {
foreach (Task<T> task in tasks.OrderByCompletion())
yield return await task;
}
}

await foreach (var task in WhenEach(tasks))
{
Console.WriteLine(await finished);
}


Источники:
-
https://youtu.be/WqXgl8EZzcs
-
https://github.com/dotnet/runtime/issues/61959
-
https://devblogs.microsoft.com/pfxteam/processing-tasks-as-they-complete/
👍40
День 1902. #ЗаметкиНаПолях
8 Способов Задать URL в Приложении
ASP.NET Core. Начало
По умолчанию приложения ASP.NET Core в .NET 8 прослушивают URL-адрес https://localhost:5000. Рассмотрим 8 различных способов изменить его.

Существует три класса URL, которые вы можете привязать:
- Адрес обратной связи (loopback) для IPv4 и IPv6 (например, https://localhost:5000, https://127.0.0.1:5000 или https://[::1]:5000) в формате: {scheme}://{loopbackAddress}:{port}
- Конкретный IP, доступный на вашем компьютере (например, https://192.168.8.31:5005), в формате {scheme}://{IPAddress}:{port}.
- «Любой» IP для заданного порта (например, https://*:6264) в формате {scheme}://*:{port}
- В .NET 8, помимо TCP, вы также можете прослушивать запросы по именованным каналам и сокетам Unix, но это тема для отдельного поста.

Порт является необязательным. Если его не указывать, будет использован порт по умолчанию (80 или 8080 для http и 443 для https).

Выбор варианта будет зависеть от механизма развёртывания. Если у вас несколько приложений на машине, может потребоваться указать явный IP. Если одно в контейнере, то вы можете использовать «любой» адрес, но обычно используют localhost.

Замечание: В формате «любой» IP не обязательно использовать *. Подойдёт всё, что не является IP или localhost: https://*, https://+, https://mydomain или https://example.org. Все варианты прослушивают любой IP-адрес. Если вы хотите обрабатывать запросы только от определённого имени хоста, необходимо дополнительно настроить фильтрацию хостов.

После выбора подходящего варианта, необходимо установить URL, к которым привязывается ASP.NET Core при запуске. Есть следующие способы:
1. UseUrls() в Program.cs.
2. WebApplication.Urls и WebApplication.Run() в Program.cs.
3. Аргументы командной строки: параметр --urls.
4. Переменные окружения для URL: DOTNET_URLS или ASPNETCORE_URLS.
5. Переменные окружения для портов: DOTNET_HTTP_PORTS или ASPNETCORE_HTTP_PORTS (и аналогично для HTTPS).
6. В appSettings.json: свойство urls.
7. В launchSettings.json: свойство applicationUrl.
8. В KestrelServerOptions.Listen() либо в IConfiguration, используя свойство Kestrel.

Далее рассмотрим их подробно.

Продолжение следует…

Источник:
https://andrewlock.net/8-ways-to-set-the-urls-for-an-aspnetcore-app/
👍14