.NET Разработчик
6.67K subscribers
450 photos
4 videos
14 files
2.16K links
Дневник сертифицированного .NET разработчика. Заметки, советы, новости из мира .NET и C#.

Для связи: @SBenzenko

Поддержать канал:
- https://boosty.to/netdeveloperdiary
- https://patreon.com/user?u=52551826
- https://pay.cloudtips.ru/p/70df3b3b
Download Telegram
День 1910. #ВопросыНаСобеседовании #ASP.NET #Architecture
Самые часто задаваемые вопросы на собеседовании по C#

31. Как бы вы подошли к обработке ошибок и отладке в распределённом приложении .NET Core с несколькими микросервисами?

Обработка ошибок и отладка в таком приложении может оказаться сложной задачей. Можно использовать несколько стратегий:

1. Централизованные логи.
Все микросервисы должны отправлять свои логи (естественно, структурированные) в централизованное место, где они сопоставляются и индексируются. Это позволит искать и визуализировать логи всех сервисов в одном месте.

2. Использование идентификаторов корреляции.
Идентификаторы корреляции (CorrelationId) — это уникальные идентификаторы, присваиваемые запросу. Затем этот идентификатор передаётся всем сервисам, участвующим в обработке этого запроса. Это позволяет отслеживать всю цепочку запросов и ответов.

3. Проверки работоспособности.
Проверки работоспособности можно реализовать для мониторинга состояния микросервисов. Они могут сообщать такие показатели, как время безотказной работы, загрузка ЦП, использование памяти и т. д.

4. Промежуточное ПО для обработки исключений.
В архитектуре микросервисов ошибки должны обрабатываться на уровне сервиса. Каждый сервис должен обрабатывать свои собственные исключения и возвращать подходящее сообщение об ошибке или код ответа.
Можно создать промежуточное ПО, которое обрабатывает каждый запрос микросервиса. Если во время выполнения запроса возникает исключение, это промежуточное ПО перехватит исключение и ответит подходящим сообщением об ошибке.
См. также «Улучшенная Обработка Исключений в ASP.NET Core 8.»

5. Использовать распределённую систему трассировки.
Она собирает данные и показатели от каждого микросервиса, а затем сопоставляет эти данные в комплексный визуальный обзор производительности системы. См. документацию.

Источник: https://dev.to/bytehide/net-core-interview-question-answers-4bc1
👍21
День 2498. #Architecture
Архитектура Вертикальных Срезов. Где Живёт Общая Логика? Начало

Архитектура Вертикальных Срезов (Vertical Slice Architecture) кажется очень удобной, когда вы с ней впервые сталкиваетесь. Не нужно прыгать между семью уровнями, чтобы добавить одно поле, не нужны десятки проектов в решении. Но при реализации более сложных функций начинают проявляться недостатки.

Допустим, у нас есть срезы CreateOrder, UpdateOrder и GetOrder. Внезапно возникает повторение: логика проверки адреса заказа в 3х местах. А подсчёт подытога, налогов и итога нужен как для корзины, так и для оформления заказа. Хочется создать общий проект или папку SharedServices. Это самый критический момент во внедрении VSA. Выберете неправильный вариант, и снова создадите связанность, от которой пытались избавиться. Выберите правильный - сохраните независимость, которой отличается VSA.

Чистая архитектура устанавливает строгие ограничения. Она точно определяет, где находится код:
- сущности - в домене (Domain),
- интерфейсы — в приложении (Application),
- реализации — в инфраструктуре (Infrastructure).
Это безопасно, предотвращает ошибки, но также препятствует использованию обходных путей, даже когда они уместны.

VSA устраняет ограничения. Она гласит: «Организуйте код по функциям, а не по техническим особенностям». Это обеспечивает скорость и гибкость, но перекладывает бремя дисциплины на вас. Что делать?

Ловушка: «Общий» мусорный ящик
Путь наименьшего сопротивления — создать проект (или папку) с именем Shared, Common или Utils. Это почти всегда ошибка.

Представьте проект Common.Services с классом OrderCalculationService:
- метод для итогов корзины (используется Cart),
- для истории доходов (используется Reporting),
- метод для форматирования счетов (используется Invoices).
3 несвязанные задачи. 3 разные причины изменений. Класс, объединяющий всё.

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

Схема принятия решений
В потенциальной ситуации совместного использования кода нужно задать 3 вопроса:

1. Это инфраструктурный или доменный код?
Инфраструктура (контексты БД, ведение журнала, HTTP-клиенты) почти всегда используются из нескольких мест. Концепции домена требуют более тщательного изучения (об этом позже).

2. Насколько стабильна концепция?
Если меняется раз в год – можно кидать в общий код. Если при каждом запросе на новую функцию, оставьте её локальной.

3. Нарушается ли «правило трёх»?
Дублирование кода 1 раз допустимо. Создание 3х копий должно насторожить. Не абстрагируйтесь, пока не достигнете трёх.

Мы решаем эту проблему рефакторингом кода. Далее рассмотрим несколько примеров.

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

Источник:
https://www.milanjovanovic.tech/blog/vertical-slice-architecture-where-does-the-shared-logic-live
👍12
День 2499. #Architecture
Архитектура Вертикальных Срезов. Где Живёт Общая Логика? Продолжение

Начало

Три уровня общего кода
Вместо бинарного разделения «общий/локальный код» мыслите тремя уровнями.

Уровень 1. Техническая инфраструктура (спокойно используйте общий код)
Чистая инфраструктура, одинаково влияющая на все срезы: логеры, фабрики подключений к БД, промежуточное ПО аутентификации, шаблон Result, конвейеры валидации и т.п. Централизуйте всё это в проекте Shared.Kernel или Infrastructure. Обратите внимание, что это также может быть папка внутри проекта. Такой код редко меняется в связи с бизнес-требованиями.
// Техническое ядро
public readonly record struct Result
{
public bool IsSuccess { get; }
public string Error { get; }

private Result(bool isSuccess, string error)
{
IsSuccess = isSuccess;
Error = error;
}

public static Result Success()
=> new(true, string.Empty);
public static Result Failure(string error)
=> new(false, error);
}


Уровень 2. Концепции домена (используйте общий код)
Вместо того, чтобы разбрасывать бизнес-правила по срезам, передавайте их в сущности и объекты-значения:
// Сущность с бизнес-логикой 
public class Order
{
public Guid Id { get; set; }
public OrderStatus Status { get; set; }
public List<OrderLine> Lines { get; set; }

public bool CanBeCancelled() =>
Status == OrderStatus.Pending;

public Result Cancel()
{
if (!CanBeCancelled())
return Result.Failure("Нельзя отменить подтверждённый заказ.");

Status = OrderStatus.Cancelled;
return Result.Success();
}
}

CancelOrder, GetOrder и UpdateOrder все используют одни бизнес-правила. Логика живёт в одном месте. Т.е. разные вертикальные срезы могут использовать одну и ту же модель домена.

Уровень 3: Логика, специфичная для конкретного объекта (сохраняйте её локально)
Логика, общая для связанных срезов, таких как CreateOrder и UpdateOrder, не обязательно должна быть глобальной. Создайте общую папку (из каждого правила есть исключения) внутри функции:
📂 Features
📂 Orders
📂 CreateOrder
📂 UpdateOrder
📂 GetOrder
📂 Shared
📄 OrderValidator.cs
📄 OrderPricingService.cs

Это также имеет скрытое преимущество. Если вы удалите функцию Orders, общая логика будет удалена вместе с ней. Никакого зомби-кода.

Наконец рассмотрим несколько сложных сценариев, которые большинство упускают из виду.

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

Источник:
https://www.milanjovanovic.tech/blog/vertical-slice-architecture-where-does-the-shared-logic-live
👍9
День 2500. #Architecture
Архитектура Вертикальных Срезов. Где Живёт Общая Логика? Окончание

Начало
Продолжение

Совместное использование между функциями
Что насчёт совместного использования кода между несвязанными функциями в VSA? CreateOrder должен проверять наличие клиента. GenerateInvoice должен рассчитывать налог. И Orders и Customers должны форматировать уведомления. Это не совсем вписывается в папку Shared определённой функции. Куда деть эту логику?

1. Действительно ли нужен общий код?
Большинство случаев «совместного использования» между функциями — это просто замаскированный доступ к данным. Если CreateOrder нужны данные о клиентах, он напрямую обращается к БД. Он не обращается к функции Customers. Каждый срез владеет своим доступом к данным. Сущность Customer является общей (находится в домене), но Orders и Customers не имеют общего сервиса.

2. Когда действительно нужна общая логика
- Логика домена (бизнес-правила, калькуляции) → Domain/Services
- Инфраструктура (внешние API, форматирование) → Infrastructure/Services
// Domain/Services/TaxCalculator.cs
public class TaxCalculator
{
public decimal CalculateTax(
Address address, decimal subtotal)
{
var rate = GetTaxRate(address.State, address.Country);
return subtotal * rate;
}
}

CreateOrder и GenerateInvoice могут использовать этот код без привязки друг к другу.

Прежде чем создавать какой-либо кросс-функциональный сервис, спросите себя: может ли эта логика размещаться в доменной сущности? Большая часть «общей бизнес-логики» на самом деле представляет собой доступ к данным, доменную логику, принадлежащую сущности, или преждевременную абстракцию.

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

3. Когда дублирование — правильный выбор
Иногда «общий» код только кажется общим:
// Features/Orders/GetOrder
public record GetOrderResponse(Guid Id, decimal Total, string Status);

// Features/Orders/CreateOrder
public record CreateOrderResponse(Guid Id, decimal Total, string Status);

Они идентичны. Возникает соблазн создать SharedOrderDto. Не поддавайтесь ему.

На следующей неделе в GetOrder понадобится URL трекинга. Но CreateOrder выполняется до отправки, поэтому не имеет URL. Если бы используете общий класс DTO, у вас появится свойство, допускающее NULL, которое в половине случаев остаётся пустым, что сбивает с толку. Дублирование дешевле, чем неправильная абстракция.

Структура Проекта
Вот как может выглядеть структура проекта VSA:
📂 src
📂 Features
│ ├📂 Orders
│ │ ├📂 CreateOrder
│ │ ├📂 UpdateOrder
│ │ └📂 Shared
│ ├📂 Customers
│ │ ├📂 GetCustomer
│ │ └📂 Shared
│ └📂 Invoices
│ └📂 GenerateInvoice
📂 Domain
│ ├📂 Entities
│ ├📂 ValueObjects
│ └📂 Services
📂 Infrastructure
│ ├📂 Persistence
│ └📂 Services
📂 Shared
📂 Behaviors

- Features — Изолированные срезы. Каждый со своими моделями запроса/ответа.
- Features/[Name]/Shared — Локальный общий код между связанными срезами.
- Domain — Сущности, объекты-значения и доменные сервисы. Общая бизнес-логика живёт здесь.
- Infrastructure — Технические вопросы.
- Shared — Только общее поведение.

Правила
1. Функции владеют своими моделями запросов/ответов. Исключений нет.
2. Перемещайте бизнес-логику в домен. Сущности и объекты-значения — лучшее место для совместного использования бизнес-правил.
3. Сохраняйте совместное использование семейств функций локальным. Если это нужно только срезам Order, храните его в Features/Orders/Shared (не стесняйтесь найти более подходящее название, чем Shared).
4. Инфраструктура по умолчанию является общей. Контексты БД, HTTP-клиенты, ведение журнала. Это технические вопросы.
5. Применяйте правило трёх. Не извлекайте данные, пока не найдёте 3 реальных использования идентичной, стабильной логики.

Источник: https://www.milanjovanovic.tech/blog/vertical-slice-architecture-where-does-the-shared-logic-live
👍16
День 2501.
Сегодня порекомендую видео от моего любимого докладчика Дилана Бити. Недавно на конференции NDC в Копенгагене он выступал с докладом “Algorithms Demystified”.

Бывало ли у вас, что вы застревали на какой-то проблеме с кодом? Возможно, реализовывали какую-то функцию в одном из своих проектов, или решали задачи на LeetCode или Advent of Code, и застряли. Вы не можете понять, как получить нужный результат. Поэтому спрашиваете у коллег, на Stack Overflow или Reddit, и получаете ответ вроде: «Да тут просто надо использовать алгоритм Дейкстры»… и ваш мозг зависает. Использовать что? Вы гуглите и обнаруживаете, что это «поиск кратчайших путей между узлами во взвешенном графе», и теперь нужно узнать, что такое «узел» и что такое «взвешенный граф»… а затем понять, как превратить всё это в работающий код.

Алгоритмы — ключ ко всем видам функций и систем, от сетей до автокоррекции, и понимание того, как они работают, поможет вам создавать более качественное программное обеспечение, исправлять едва заметные ошибки и решать задачи на Advent of Code. В этом докладе Дилан расскажет о некоторых из его любимых алгоритмов, объяснит их важность и поможет вам понять, что они делают и как.
👍10