День 2641. #ЗаметкиНаПолях
Паттерн «Интерпретатор» в .NET. Начало
Когда бизнес-правила похоронены в цепочках if-else.
Система скидок начиналась с простого: 10% на заказы свыше $100. Одно условие, одно правило. Затем отдел маркетинга захотел: "20% для VIP-клиентов И заказом свыше $200." Затем: "Бесплатную доставку товаров категории "Электроника" ИЛИ за заказ свыше $500." И т.д., и т.п.
Теперь метод предоставления скидок — это 150 строк вложенных условных операторов, к которым никто не хочет прикасаться:
Каждое новое правило требует модификации кода, повторного развёртывания и тестирования всей цепочки. Маркетинг не может обновлять правила без участия разработчиков. А логика совершенно непрозрачна — никто не может прочитать её и понять весь набор правил.
Проблема в том, что эти правила представляют собой бизнес-логику, которая часто меняется, но они заблокированы внутри скомпилированного кода. Нужен способ представить правила в виде данных — чего-то, что можно анализировать, компоновать и динамически оценивать.
Паттерн «Интерпретатор»
Паттерн «Интерпретатор» определяет грамматику для языка и предоставляет интерпретатор, который оценивает выражения на этом языке. Каждое правило в грамматике - класс. Сложные правила компонуются из простых.
Определим интерфейс выражений и атомарные выражения:
Теперь нетерминальные выражения – логические действия:
Составляем правила из выражений:
Правила — это компонуемые структуры данных. Вы можете хранить их, сериализовать и создавать из конфигурации.
Почему это лучше
1. Правила — это данные, а не код. Вы можете хранить определения правил в БД и создавать деревья выражений во время выполнения. Для новых правил не требуется повторное развёртывание.
2. Компонуемость. Операторы И, ИЛИ и НЕ объединяют любые выражения. Сложные правила строятся из простых, протестированных компонентов.
3. Тестируемость. Каждое выражение представляет собой отдельный класс с одним методом. Тестируйте OrderTotalGreaterThan независимо от всего остального.
Окончание следует…
Источник: https://thecodeman.net/posts/interpreter-pattern-in-dotnet
Паттерн «Интерпретатор» в .NET. Начало
Когда бизнес-правила похоронены в цепочках if-else.
Система скидок начиналась с простого: 10% на заказы свыше $100. Одно условие, одно правило. Затем отдел маркетинга захотел: "20% для VIP-клиентов И заказом свыше $200." Затем: "Бесплатную доставку товаров категории "Электроника" ИЛИ за заказ свыше $500." И т.д., и т.п.
Теперь метод предоставления скидок — это 150 строк вложенных условных операторов, к которым никто не хочет прикасаться:
public decimal CalculateDiscount(
Order order, Customer customer)
{
if (customer.IsVip && order.Total > 200)
return order.Total * 0.20m;
else if (order.Total > 100)
return order.Total * 0.10m;
else if (order.Items.Any(i => i.Category == "Electronics") || order.Total > 500)
order.Shipping = 0;
// … ещё 20 условий
return order.Total;
}
Каждое новое правило требует модификации кода, повторного развёртывания и тестирования всей цепочки. Маркетинг не может обновлять правила без участия разработчиков. А логика совершенно непрозрачна — никто не может прочитать её и понять весь набор правил.
Проблема в том, что эти правила представляют собой бизнес-логику, которая часто меняется, но они заблокированы внутри скомпилированного кода. Нужен способ представить правила в виде данных — чего-то, что можно анализировать, компоновать и динамически оценивать.
Паттерн «Интерпретатор»
Паттерн «Интерпретатор» определяет грамматику для языка и предоставляет интерпретатор, который оценивает выражения на этом языке. Каждое правило в грамматике - класс. Сложные правила компонуются из простых.
Определим интерфейс выражений и атомарные выражения:
// Контекст - данные, которые будут оцениваться в выражениях
public class RuleContext(Order order, Customer customer)
{
public Order Order { get; } = order;
public Customer Customer { get; } = customer;
}
// Абстрактное выражение
public interface IExpression
{
bool Interpret(RuleContext ctx);
}
// Окончательные выражения: атомарные условия
public class OrderTotalGreaterThan(decimal threshold)
: IExpression
{
public bool Interpret(RuleContext ctx)
=> context.Order.Total > threshold;
}
public class CustomerIsVip : IExpression
{
public bool Interpret(RuleContext ctx)
=> context.Customer.IsVip;
}
public class OrderContainsCategory(string category)
: IExpression
{
public bool Interpret(RuleContext ctx)
=> ctx.Order.Items.Any(i =>
i.Category.Equals(category,
StringComparison.OrdinalIgnoreCase));
}
// …
Теперь нетерминальные выражения – логические действия:
// И
public class AndExpression(IExpression left, IExpression right)
: IExpression
{
public bool Interpret(RuleContext ctx)
=> left.Interpret(ctx) && right.Interpret(ctx);
}
// ИЛИ
public class OrExpression(IExpression left, IExpression right)
: IExpression
{
public bool Interpret(RuleContext ctx)
=> left.Interpret(ctx) || right.Interpret(ctx);
}
// НЕ
public class NotExpression(IExpression expression)
: IExpression
{
public bool Interpret(RuleContext ctx)
=> !expression.Interpret(ctx);
}
Составляем правила из выражений:
// VIP-клиент и заказ > $200
var vipHighValueRule = new AndExpression(
new CustomerIsVip(),
new OrderTotalGreaterThan(200));
var ctx = new RuleContext(order, customer);
if (vipHighValueRule.Interpret(ctx))
discount = 0.20m;
Правила — это компонуемые структуры данных. Вы можете хранить их, сериализовать и создавать из конфигурации.
Почему это лучше
1. Правила — это данные, а не код. Вы можете хранить определения правил в БД и создавать деревья выражений во время выполнения. Для новых правил не требуется повторное развёртывание.
2. Компонуемость. Операторы И, ИЛИ и НЕ объединяют любые выражения. Сложные правила строятся из простых, протестированных компонентов.
3. Тестируемость. Каждое выражение представляет собой отдельный класс с одним методом. Тестируйте OrderTotalGreaterThan независимо от всего остального.
Окончание следует…
Источник: https://thecodeman.net/posts/interpreter-pattern-in-dotnet
👍6
День 2642. #ЗаметкиНаПолях
Паттерн «Интерпретатор» в .NET. Расширенное использование
Начало
1. Создание правил из конфигурации
Парсим правила из JSON или БД:
Определение правила в JSON:
Теперь отдел маркетинга может определять правила в UI панели управления. RuleEngine анализирует и оценивает их без изменения кода.
2. Парсинг выражений для вычисляемых полей
Аналогично можно создавать математические выражения:
Когда не использовать
1. Для сложных правил. Если нужны циклы, функции или сложный синтаксис, используйте подходящий генератор парсеров (ANTLR) или существующий скриптовый движок (Roslyn, Lua). Паттерн «Интерпретатор» плохо масштабируется для сложных языков.
2. Важна производительность. Каждый вызов Interpret() проходит по дереву выражений. Для часто используемых путей с миллионами вычислений скомпилированные выражения (Expression<T>.Compile()) на порядки быстрее.
3. Правила редко меняются. Если правила стабильны и меняются раз в год, затраты на создание интерпретатора не оправданы. Просто пишите условия напрямую.
«Интерпретатор» избыточен?
Для 3-4 фиксированных условий — да. Просто используйте if-else. Паттерн особенно эффективен, когда у вас более 20 правил, которые регулярно меняются и позволяют создавать комбинации без перекомпиляции кода.
Альтернативы
Для оценки во время выполнения деревья выражений C# Expression<T> компилируются в IL. Для простой оценки правил может подойти словарь делегатов или паттерн «Стратегия».
Источник: https://thecodeman.net/posts/interpreter-pattern-in-dotnet
Паттерн «Интерпретатор» в .NET. Расширенное использование
Начало
1. Создание правил из конфигурации
Парсим правила из JSON или БД:
public class RuleEngine
{
public IExpression BuildFromConfig(
RuleDefinition def) => def.Type switch
{
"OrderTotalGreaterThan" =>
new OrderTotalGreaterThan(
def.GetParam<decimal>("threshold")),
"CustomerIsVip" =>
new CustomerIsVip(),
"OrderContainsCategory" =>
new OrderContainsCategory(
def.GetParam<string>("category")),
"AND" =>
new AndExpression(
BuildFromConfig(def.Left!),
BuildFromConfig(def.Right!)),
"OR" =>
new OrExpression(
BuildFromConfig(def.Left!),
BuildFromConfig(def.Right!)),
"NOT" =>
new NotExpression(BuildFromConfig(def.Left!)),
_ => throw new InvalidOperationException(
$"Неизвестный тип: {def.Type}")
};
}
Определение правила в JSON:
{
"type": "AND",
"left": { "type": "CustomerIsVip" },
"right": { "type": "OrderTotalGreaterThan", "params": { "threshold": 200 } }
}Теперь отдел маркетинга может определять правила в UI панели управления. RuleEngine анализирует и оценивает их без изменения кода.
2. Парсинг выражений для вычисляемых полей
Аналогично можно создавать математические выражения:
public interface IMathExpression
{
decimal Evaluate(Dictionary<string, decimal> variables);
}
public class NumberLiteral(decimal value)
: IMathExpression
{
public decimal Evaluate(Dictionary<string, decimal> variables)
=> value;
}
public class Variable(string name)
: IMathExpression
{
public decimal Evaluate(Dictionary<string, decimal> variables)
=> variables[name];
}
public class Multiply(IMathExpression left, IMathExpression right)
: IMathExpression
{
public decimal Evaluate(Dictionary<string, decimal> variables)
=> left.Evaluate(variables) * right.Evaluate(variables);
}
// Выражение: price * quantity * (1 - discount)
var totalExpr = new Multiply(
new Multiply(new Variable("price"), new Variable("quantity")),
new Subtract(new NumberLiteral(1), new Variable("discountRate")));
var vars = new Dictionary<string, decimal>
{
["price"] = 29.99m, ["quantity"] = 3, ["discount"] = 0.10m
};
var total = totalExpr.Evaluate(vars); // 80.973
Когда не использовать
1. Для сложных правил. Если нужны циклы, функции или сложный синтаксис, используйте подходящий генератор парсеров (ANTLR) или существующий скриптовый движок (Roslyn, Lua). Паттерн «Интерпретатор» плохо масштабируется для сложных языков.
2. Важна производительность. Каждый вызов Interpret() проходит по дереву выражений. Для часто используемых путей с миллионами вычислений скомпилированные выражения (Expression<T>.Compile()) на порядки быстрее.
3. Правила редко меняются. Если правила стабильны и меняются раз в год, затраты на создание интерпретатора не оправданы. Просто пишите условия напрямую.
«Интерпретатор» избыточен?
Для 3-4 фиксированных условий — да. Просто используйте if-else. Паттерн особенно эффективен, когда у вас более 20 правил, которые регулярно меняются и позволяют создавать комбинации без перекомпиляции кода.
Альтернативы
Для оценки во время выполнения деревья выражений C# Expression<T> компилируются в IL. Для простой оценки правил может подойти словарь делегатов или паттерн «Стратегия».
Источник: https://thecodeman.net/posts/interpreter-pattern-in-dotnet
👍1
День 2643. #ВопросыНаСобеседовании
Марк Прайс предложил свой набор из 60 вопросов (как технических, так и на софт-скилы), которые могут задать на собеседовании.
31. Паттерн MVC
«Расскажите, что такое паттерн MVC и как вы его реализовали в своих проектах? Приведите пример того, как вы использовали MVC.»
Хороший ответ
Паттерн MVC (Model-View-Controller) — это принцип проектирования, который разделяет приложение на три взаимосвязанных компонента. Такое разделение помогает управлять сложностью, способствует организации кода и поддерживает масштабируемость:
1. Модель - слой данных и бизнес-логики приложения. Она отвечает за хранение данных, их обработку и определение бизнес-правил.
2. Представление - обрабатывает отображение данных, получая модель от контроллера. Оно только отображает информацию пользователю и отправляет команды пользователя контроллеру.
3. Контроллер - выступает в качестве посредника между моделью и представлением, получая данные из модели и решая, какое представление отображать.
В своих проектах я использовал паттерн MVC, чтобы обеспечить надлежащее разделение задач, что упрощает поддержку и расширение приложения. Например:
В этом примере ProductsController получает данные о продуктах, используя репозиторий IProductRepo, который абстрагирует логику доступа к данным. Полученные данные затем передаются в представление Index, которое отвечает за отображение информации о продуктах. Такое разделение позволяет вносить изменения в модель БД или бизнес-логику, не затрагивая логику представления, и наоборот, тем самым соблюдая принцип единственной ответственности.
Такой подход не только делает архитектуру яснее, но и повышает тестируемость приложения. Каждый компонент может быть протестирован независимо, что крайне важно для поддержания высокого качества кода по мере масштабирования приложения.
Часто встречающийся плохой ответ
«MVC — это просто обеспечение наличия моделей, представлений и контроллеров в проекте. Нужно поместить HTML-код в представления, код получения из БД в модели и использовать контроллеры для связи всего этого».
Почему это неправильно
- Чрезмерное упрощение ролей: этот ответ упрощает роли моделей, представлений и контроллеров, не понимая их конкретных обязанностей.
- Отсутствие разделения ответственности: ответ недостаточно рассматривает разделение ответственности, которое является ключевым преимуществом использования MVC. Просто связывая компоненты, разработчик упускает суть MVC, которая заключается в максимально возможной децентрализации этих компонентов для обеспечения независимой разработки, тестирования и сопровождения.
- Непонимание лучших практик в архитектуре MVC, таких как размещение бизнес-логики вне контроллеров и представлений.
Эта ошибка часто возникает из-за поверхностного понимания паттерна MVC, возможно, из-за ограниченного опыта работы над проектами, где MVC использовался эффективно, или из-за сосредоточенности на простом запуске приложения без понимания основных принципов проектирования MVC.
Источник: https://github.com/markjprice/tools-skills-net8/blob/main/docs/interview-qa/readme.md
Марк Прайс предложил свой набор из 60 вопросов (как технических, так и на софт-скилы), которые могут задать на собеседовании.
31. Паттерн MVC
«Расскажите, что такое паттерн MVC и как вы его реализовали в своих проектах? Приведите пример того, как вы использовали MVC.»
Хороший ответ
Паттерн MVC (Model-View-Controller) — это принцип проектирования, который разделяет приложение на три взаимосвязанных компонента. Такое разделение помогает управлять сложностью, способствует организации кода и поддерживает масштабируемость:
1. Модель - слой данных и бизнес-логики приложения. Она отвечает за хранение данных, их обработку и определение бизнес-правил.
2. Представление - обрабатывает отображение данных, получая модель от контроллера. Оно только отображает информацию пользователю и отправляет команды пользователя контроллеру.
3. Контроллер - выступает в качестве посредника между моделью и представлением, получая данные из модели и решая, какое представление отображать.
В своих проектах я использовал паттерн MVC, чтобы обеспечить надлежащее разделение задач, что упрощает поддержку и расширение приложения. Например:
// Модель
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
// Контроллер
public class ProductsController : Controller
{
private readonly IProductRepo _repo;
public ProductsController(IProductRepo repo)
{
_repo = repo;
}
public async Task<IActionResult> Index()
{
var products = await _repo.GetAllAsync();
// Передаём модель в представление
return View(products);
}
}
// Представление (Index.cshtml)
@model IEnumerable<Product>
<h2>Продукты</h2>
<ul>
@foreach(var product in Model)
{
<li>@product.Name - $@product.Price</li>
}
</ul>
В этом примере ProductsController получает данные о продуктах, используя репозиторий IProductRepo, который абстрагирует логику доступа к данным. Полученные данные затем передаются в представление Index, которое отвечает за отображение информации о продуктах. Такое разделение позволяет вносить изменения в модель БД или бизнес-логику, не затрагивая логику представления, и наоборот, тем самым соблюдая принцип единственной ответственности.
Такой подход не только делает архитектуру яснее, но и повышает тестируемость приложения. Каждый компонент может быть протестирован независимо, что крайне важно для поддержания высокого качества кода по мере масштабирования приложения.
Часто встречающийся плохой ответ
«MVC — это просто обеспечение наличия моделей, представлений и контроллеров в проекте. Нужно поместить HTML-код в представления, код получения из БД в модели и использовать контроллеры для связи всего этого».
Почему это неправильно
- Чрезмерное упрощение ролей: этот ответ упрощает роли моделей, представлений и контроллеров, не понимая их конкретных обязанностей.
- Отсутствие разделения ответственности: ответ недостаточно рассматривает разделение ответственности, которое является ключевым преимуществом использования MVC. Просто связывая компоненты, разработчик упускает суть MVC, которая заключается в максимально возможной децентрализации этих компонентов для обеспечения независимой разработки, тестирования и сопровождения.
- Непонимание лучших практик в архитектуре MVC, таких как размещение бизнес-логики вне контроллеров и представлений.
Эта ошибка часто возникает из-за поверхностного понимания паттерна MVC, возможно, из-за ограниченного опыта работы над проектами, где MVC использовался эффективно, или из-за сосредоточенности на простом запуске приложения без понимания основных принципов проектирования MVC.
Источник: https://github.com/markjprice/tools-skills-net8/blob/main/docs/interview-qa/readme.md
👎2
День 2644. #ЧтоНовенького
Первые Очертания Visual Studio 2027
Мадс Кристенсен из Microsoft на конференции VSLive! в Лас-Вегасе (плейлист докладов, кстати, вот тут) рассказал, что нового будет в Visual Studio 2027.
Модель непрерывного выпуска
Вместо того чтобы позиционировать 2027 как традиционную новую основную версию, которая выходит как отдельный продукт, представленная на VSLive! дорожная карта описывает более стабильное ежемесячное развитие с появлением новых возможностей по ходу.
Т.е. Microsoft переводит VS на модель непрерывного выпуска. Стабильный канал General Availability получает ежемесячные обновления, а канал Insider развивается - еженедельные, предоставляя разработчикам ранний доступ к функциям. Так переход от VS 2026 к VS 2027 – это обновление существующей среды на месте, а не переустановка, и он будет скорей последовательностью непрерывных обновлений, а не единым релизом. Теперь командам разработки не придётся планировать миграцию инструментов отдельно от обычных циклов обновлений. Поэтапные обновления также приблизят IDE к темпам изменений в рабочих процессах разработки .NET и C# (VS 2027 обещают выпустить вместе с релизом новой версии .NET в ноябре).
ИИ и профессиональный разработчик
Разработчики по-прежнему проводят время перед экранами, занимаясь написанием кода, отладкой приложений и управлением ПО, даже если они начинают использовать инструменты ИИ в некоторых аспектах своей работы. Существующие навыки остаются важными, поскольку системам ИИ по-прежнему не хватает более широкого контекста, который разработчики подразумевают в своих системах, организациях и планах на будущее. Хотя, в написании отдельных частей кода ИИ уже показывает неплохие результаты. Поэтому теперь разработчики, вероятно, будут тратить больше времени на проверку и оценку кода, независимо от того, написан ли он людьми или сгенерирован с помощью ИИ.
Проверка кода с помощью профилирования и агентов
Этот сдвиг повышает важность инструментов, помогающих разработчикам понимать и проверять ПО. Модульные и интеграционные тесты могут сократить объём ручной проверки, предоставляя разработчикам больше уверенности в том, что изменения не нарушают существующее поведение.
В демонстрации новой возможности VS «Профилирование с помощью Copilot» Copilot запустил модульный тест для популярной библиотеки QR Coder в профилировщике, установил базовый уровень производительности, проанализировал полученную трассировку, выявил ресурсоёмкие пути в коде (в частности, вычисления с плавающей запятой), предложил оптимизации, пересобрал проект, повторно запустил тест для подтверждения корректности и измерил результирующее улучшение производительности примерно на 63%.
Эта функция будет полезна даже без ИИ, поскольку разработчики теперь могут использовать модульные тесты в качестве отправной точки для профилирования с целью выявления ресурсоёмких участков кода. Добавление ИИ к этому рабочему процессу помогает сократить разрыв между обнаружением проблемы производительности и пониманием того, как её улучшить.
Ожидается, что VS будет развиваться областях тестирования, диагностики, такой как отладка и профилирование, ускорения процессов сборки и запуска, интеграции с другими системами, участвующими в доставке ПО, проверки кода и ИИ. Обозреватель тестов VS обновлялся не так быстро, как другие инструменты, и это ключевая область для модернизации.
Главный посыл сессии Кристенсена заключался в том, что VS формируется для среды разработки, в которой ИИ всё больше присутствует, но не в качестве замены разработчиков. Кристенсен утверждает, что разработчикам по-прежнему потребуются сильные навыки в программировании, отладке, тестировании и понимании того, как системы взаимодействуют друг с другом, — и что эти навыки могут стать ещё более важными по мере того, как ИИ будет всё больше использоваться в рабочем процессе.
Источник: https://visualstudiomagazine.com/articles/2026/04/17/at-vslive-mads-k-lets-the-cat-out-of-the-bag-on-visual-studio-2027.aspx
Первые Очертания Visual Studio 2027
Мадс Кристенсен из Microsoft на конференции VSLive! в Лас-Вегасе (плейлист докладов, кстати, вот тут) рассказал, что нового будет в Visual Studio 2027.
Модель непрерывного выпуска
Вместо того чтобы позиционировать 2027 как традиционную новую основную версию, которая выходит как отдельный продукт, представленная на VSLive! дорожная карта описывает более стабильное ежемесячное развитие с появлением новых возможностей по ходу.
Т.е. Microsoft переводит VS на модель непрерывного выпуска. Стабильный канал General Availability получает ежемесячные обновления, а канал Insider развивается - еженедельные, предоставляя разработчикам ранний доступ к функциям. Так переход от VS 2026 к VS 2027 – это обновление существующей среды на месте, а не переустановка, и он будет скорей последовательностью непрерывных обновлений, а не единым релизом. Теперь командам разработки не придётся планировать миграцию инструментов отдельно от обычных циклов обновлений. Поэтапные обновления также приблизят IDE к темпам изменений в рабочих процессах разработки .NET и C# (VS 2027 обещают выпустить вместе с релизом новой версии .NET в ноябре).
ИИ и профессиональный разработчик
Разработчики по-прежнему проводят время перед экранами, занимаясь написанием кода, отладкой приложений и управлением ПО, даже если они начинают использовать инструменты ИИ в некоторых аспектах своей работы. Существующие навыки остаются важными, поскольку системам ИИ по-прежнему не хватает более широкого контекста, который разработчики подразумевают в своих системах, организациях и планах на будущее. Хотя, в написании отдельных частей кода ИИ уже показывает неплохие результаты. Поэтому теперь разработчики, вероятно, будут тратить больше времени на проверку и оценку кода, независимо от того, написан ли он людьми или сгенерирован с помощью ИИ.
Проверка кода с помощью профилирования и агентов
Этот сдвиг повышает важность инструментов, помогающих разработчикам понимать и проверять ПО. Модульные и интеграционные тесты могут сократить объём ручной проверки, предоставляя разработчикам больше уверенности в том, что изменения не нарушают существующее поведение.
В демонстрации новой возможности VS «Профилирование с помощью Copilot» Copilot запустил модульный тест для популярной библиотеки QR Coder в профилировщике, установил базовый уровень производительности, проанализировал полученную трассировку, выявил ресурсоёмкие пути в коде (в частности, вычисления с плавающей запятой), предложил оптимизации, пересобрал проект, повторно запустил тест для подтверждения корректности и измерил результирующее улучшение производительности примерно на 63%.
Эта функция будет полезна даже без ИИ, поскольку разработчики теперь могут использовать модульные тесты в качестве отправной точки для профилирования с целью выявления ресурсоёмких участков кода. Добавление ИИ к этому рабочему процессу помогает сократить разрыв между обнаружением проблемы производительности и пониманием того, как её улучшить.
Ожидается, что VS будет развиваться областях тестирования, диагностики, такой как отладка и профилирование, ускорения процессов сборки и запуска, интеграции с другими системами, участвующими в доставке ПО, проверки кода и ИИ. Обозреватель тестов VS обновлялся не так быстро, как другие инструменты, и это ключевая область для модернизации.
Главный посыл сессии Кристенсена заключался в том, что VS формируется для среды разработки, в которой ИИ всё больше присутствует, но не в качестве замены разработчиков. Кристенсен утверждает, что разработчикам по-прежнему потребуются сильные навыки в программировании, отладке, тестировании и понимании того, как системы взаимодействуют друг с другом, — и что эти навыки могут стать ещё более важными по мере того, как ИИ будет всё больше использоваться в рабочем процессе.
Источник: https://visualstudiomagazine.com/articles/2026/04/17/at-vslive-mads-k-lets-the-cat-out-of-the-bag-on-visual-studio-2027.aspx
👍3
День 2645. #ЗаметкиНаПолях
Тестовая Пирамида — Ложь (и Что Делать Вместо Этого). Начало
Автор оригинала: Milan Jovanović
Наверное, никогда мои проекты не имели канонической тестовой пирамиды, как на рисунке ниже. Широкое основание модульных тестов, узкое середина интеграционных тестов, крошечный кусочек сквозных тестов на вершине. Я согласно кивал на конференциях, но делал по-своему.
Откуда взялась пирамида
Пирамида была популяризирована Майком Коном в 2009 году, когда интеграционные тесты означали общий сервер БД, нестабильный CI и 20-минутные сборки. Модульные тесты с моками были прагматичным компромиссом.
Этот мир ушёл в прошлое. С помощью Testcontainers можно быстро запустить PostgreSQL, Redis и RabbitMQ в новом контейнере для каждого тестового класса. Aspire Test Host идёт ещё дальше, подключая весь граф вашего приложения. Аргумент о том, что реальные зависимости слишком затратны, по сути, больше не актуален. Но рекомендации не обновились.
Ошибка, которая меня убедила
Пару лет назад у меня был сервис с 94% покрытием модульными тестами. Все тесты были «зелеными». Но в один прекрасный день пользователь сообщил, что удаление учётной записи на самом деле не приводит к удалению его данных. Метод был проще некуда:
Да, в нём забыли вызвать
Один интеграционный тест с реальной БД обнаружил бы это в миг. В этом суть: чем меньше инвариантов ваш стиль тестирования заставляет вас запоминать, тем меньше ошибок проскальзывает.
В чём на самом деле хороши модульные тесты
Модульные тесты оправдывают себя, когда логика нетривиальна, чиста (без операций ввода-вывода, без асинхронности, без случайности) и сложна для проверки от начала до конца. Это вариантов кода вроде объектов-значений и сложных моделей домена, расчётов цен и налогов, парсеров, мапперов, сериализаторов и т.п.
Заметили, чего нет в этом списке? Сервисов, обработчиков, контроллеров, репозиториев, инфраструктуры. Они находятся на стыке модулей, и именно в этом стыке и кроются настоящие ошибки.
Что же делать вместо этого?
Окончание следует…
Источник: https://www.milanjovanovic.tech/blog/the-test-pyramid-is-a-lie-and-what-i-do-instead
Тестовая Пирамида — Ложь (и Что Делать Вместо Этого). Начало
Автор оригинала: Milan Jovanović
Наверное, никогда мои проекты не имели канонической тестовой пирамиды, как на рисунке ниже. Широкое основание модульных тестов, узкое середина интеграционных тестов, крошечный кусочек сквозных тестов на вершине. Я согласно кивал на конференциях, но делал по-своему.
Откуда взялась пирамида
Пирамида была популяризирована Майком Коном в 2009 году, когда интеграционные тесты означали общий сервер БД, нестабильный CI и 20-минутные сборки. Модульные тесты с моками были прагматичным компромиссом.
Этот мир ушёл в прошлое. С помощью Testcontainers можно быстро запустить PostgreSQL, Redis и RabbitMQ в новом контейнере для каждого тестового класса. Aspire Test Host идёт ещё дальше, подключая весь граф вашего приложения. Аргумент о том, что реальные зависимости слишком затратны, по сути, больше не актуален. Но рекомендации не обновились.
Ошибка, которая меня убедила
Пару лет назад у меня был сервис с 94% покрытием модульными тестами. Все тесты были «зелеными». Но в один прекрасный день пользователь сообщил, что удаление учётной записи на самом деле не приводит к удалению его данных. Метод был проще некуда:
public async Task Handle(DeleteAccountCommand command, CancellationToken ct)
{
var account = await _repo.GetByIdAsync(command.AccountId, ct);
account.MarkAsDeleted();
}
Да, в нём забыли вызвать
SaveChangesAsync(). И тест для этого случая просто не был написан. Можно проверить, был ли вызван SaveChangesAsync в методе с помощью мока. Но в кодовой базе, где этот тест — один из сотен тестов обработчиков, каждый со своей настройкой мока и своим списком проверок, про это просто забыли. И покрытие тестами показывало, что всё в порядке. Один интеграционный тест с реальной БД обнаружил бы это в миг. В этом суть: чем меньше инвариантов ваш стиль тестирования заставляет вас запоминать, тем меньше ошибок проскальзывает.
В чём на самом деле хороши модульные тесты
Модульные тесты оправдывают себя, когда логика нетривиальна, чиста (без операций ввода-вывода, без асинхронности, без случайности) и сложна для проверки от начала до конца. Это вариантов кода вроде объектов-значений и сложных моделей домена, расчётов цен и налогов, парсеров, мапперов, сериализаторов и т.п.
Заметили, чего нет в этом списке? Сервисов, обработчиков, контроллеров, репозиториев, инфраструктуры. Они находятся на стыке модулей, и именно в этом стыке и кроются настоящие ошибки.
Что же делать вместо этого?
Окончание следует…
Источник: https://www.milanjovanovic.tech/blog/the-test-pyramid-is-a-lie-and-what-i-do-instead
👍5
День 2646. #ЗаметкиНаПолях
Тестовая Пирамида — Ложь (и Что Делать Вместо Этого). Окончание
Начало
Что делать вместо тестовой пирамиды
Вот структура тестов для типичного сервиса .NET или модульного монолита.
Уровень 1: Тонкая база модульных тестов (15-25% тестов)
Вся логика домена. Никаких контейнеров или моков. Микросекунды на тест. Для этого и существуют модульные тесты. Если модульному тесту нужен мок, то он будет на уровне интеграции.
Уровень 2: Толстый средний слой интеграционных тестов (60-70%)
Все обработчики команд и запросов, все конечные точки HTTP, все потребители сообщений тестируются на реальной инфраструктуре внутри тестовых контейнеров. В модульном монолите именно здесь проверяется корректность взаимодействия модулей друг с другом через их публичные API.
Эти тесты проверяют слой HTTP, маршрутизацию, привязку модели, авторизацию, обработчики, контексты, EF Core и PostgreSQL. Они доказывают то, что вас действительно интересует: когда я вызываю эту конечную точку, строка в базе изменяется. И это происходит без необходимости кому-либо помнить о вызове SaveChangesAsync и проверке, вызывается ли он.
Уровень 3: Небольшое количество сквозных тестов (<10%)
Только те потоки, где скрытый сбой может представлять коммерческую проблему или проблему соответствия требованиям. Регистрация, оплата, возврат средств, сброс пароля, двухфакторная аутентификация. Они медленные и иногда нестабильные, но они выявляют тот единственный режим отказа, который все остальные тесты пропускают: система в целом продолжает работать.
Уровень 0: Архитектурные и контрактные тесты
Часто забываются, но они являются частью набора тестов. Архитектурные тесты обеспечивают соблюдение разделения на слои и границ модулей. Контрактные тесты проверяют, что схемы сообщений и формат API не меняются. Они выполняются за миллисекунды и выявляют ошибки типа «через шесть месяцев кто-то сломает это, не заметив».
Полученная форма больше напоминает ромб, чем пирамиду. Толстая середина — это намеренное решение. Именно отсюда и берётся уверенность в тестах.
Обычные возражения
«Интеграционные тесты медленные». Мой типичный набор интеграционных тестов выполняется за 2-4 минуты в CI с повторным использованием Testcontainers и распараллеливанием тестовых классов. Медленнее, чем модульные тесты? Да. Но быстрее, чем обнаружение ошибки в продакшене.
«Моки хороши, если вы дисциплинированы». Возможно. Но в каждой крупной кодовой базе, которую я проверял и которая сильно полагалась на моки, была одна и та же патология: тесты проходят после рефакторинга, даже если рефакторинг сломал продакшен. Это не проблема дисциплины. Это неправильное использование инструмента.
Итого
Пирамида тестирования была хорошим советом для инфраструктуры 2009 года, но является плохим советом для инфраструктуры 2026 года. Testcontainers и Aspire изменили экономику, и самый быстрый цикл обратной связи, который по-прежнему сообщает правду, теперь — это интеграционный тест с реальными зависимостями. Модульные тесты по-прежнему должны быть сосредоточены на чистой логике предметной области. Всё, что переходит через границы модулей, должно быть на уровне интеграции.
Источник: https://www.milanjovanovic.tech/blog/the-test-pyramid-is-a-lie-and-what-i-do-instead
Тестовая Пирамида — Ложь (и Что Делать Вместо Этого). Окончание
Начало
Что делать вместо тестовой пирамиды
Вот структура тестов для типичного сервиса .NET или модульного монолита.
Уровень 1: Тонкая база модульных тестов (15-25% тестов)
Вся логика домена. Никаких контейнеров или моков. Микросекунды на тест. Для этого и существуют модульные тесты. Если модульному тесту нужен мок, то он будет на уровне интеграции.
[Fact]
public void Confirm_WhenPending_TransitionsToConfirmed()
{
var order = Order.Create(
CustomerId.New(), Money.Usd(100));
order.Confirm();
order.Status.Should()
.Be(OrderStatus.Confirmed);
order.DomainEvents.Should()
.ContainSingle(e => e is OrderConfirmedEvent);
}
Уровень 2: Толстый средний слой интеграционных тестов (60-70%)
Все обработчики команд и запросов, все конечные точки HTTP, все потребители сообщений тестируются на реальной инфраструктуре внутри тестовых контейнеров. В модульном монолите именно здесь проверяется корректность взаимодействия модулей друг с другом через их публичные API.
public class DeleteAccountTests(
IntegrationTestWebAppFactory factory)
: BaseIntegrationTest(factory)
{
[Fact]
public async Task DeleteAccount_MarksAccountDeleted()
{
var acc = await CreateAccountAsync();
var resp = await HttpClient
.DeleteAsync($"/accounts/{acc.Id}");
resp.StatusCode.Should().Be(HttpStatusCode.NoContent);
var stored = await DbContext.Accounts
.IgnoreQueryFilters()
.SingleAsync(a => a.Id == acc.Id);
stored.IsDeleted.Should().BeTrue();
}
}
Эти тесты проверяют слой HTTP, маршрутизацию, привязку модели, авторизацию, обработчики, контексты, EF Core и PostgreSQL. Они доказывают то, что вас действительно интересует: когда я вызываю эту конечную точку, строка в базе изменяется. И это происходит без необходимости кому-либо помнить о вызове SaveChangesAsync и проверке, вызывается ли он.
Уровень 3: Небольшое количество сквозных тестов (<10%)
Только те потоки, где скрытый сбой может представлять коммерческую проблему или проблему соответствия требованиям. Регистрация, оплата, возврат средств, сброс пароля, двухфакторная аутентификация. Они медленные и иногда нестабильные, но они выявляют тот единственный режим отказа, который все остальные тесты пропускают: система в целом продолжает работать.
Уровень 0: Архитектурные и контрактные тесты
Часто забываются, но они являются частью набора тестов. Архитектурные тесты обеспечивают соблюдение разделения на слои и границ модулей. Контрактные тесты проверяют, что схемы сообщений и формат API не меняются. Они выполняются за миллисекунды и выявляют ошибки типа «через шесть месяцев кто-то сломает это, не заметив».
Полученная форма больше напоминает ромб, чем пирамиду. Толстая середина — это намеренное решение. Именно отсюда и берётся уверенность в тестах.
Обычные возражения
«Интеграционные тесты медленные». Мой типичный набор интеграционных тестов выполняется за 2-4 минуты в CI с повторным использованием Testcontainers и распараллеливанием тестовых классов. Медленнее, чем модульные тесты? Да. Но быстрее, чем обнаружение ошибки в продакшене.
«Моки хороши, если вы дисциплинированы». Возможно. Но в каждой крупной кодовой базе, которую я проверял и которая сильно полагалась на моки, была одна и та же патология: тесты проходят после рефакторинга, даже если рефакторинг сломал продакшен. Это не проблема дисциплины. Это неправильное использование инструмента.
Итого
Пирамида тестирования была хорошим советом для инфраструктуры 2009 года, но является плохим советом для инфраструктуры 2026 года. Testcontainers и Aspire изменили экономику, и самый быстрый цикл обратной связи, который по-прежнему сообщает правду, теперь — это интеграционный тест с реальными зависимостями. Модульные тесты по-прежнему должны быть сосредоточены на чистой логике предметной области. Всё, что переходит через границы модулей, должно быть на уровне интеграции.
Источник: https://www.milanjovanovic.tech/blog/the-test-pyramid-is-a-lie-and-what-i-do-instead
1👍6
День 2647. #ProjectManagement
Как Проваливаются Разработчики ПО. Начало
«Разработчики ПО терпят неудачу двумя способами: они либо делают продукт не так, либо делают не тот продукт».
Эти два вида неудачи стоит рассматривать независимо друг от друга, т.к. у них разные первопричины и последствия. И ИИ-агенты сталкиваются с теми же проблемами, но могут делать и то, и другое гораздо быстрее людей.
1. Неправильная разработка продукта
Техническое исполнение неверное. Требования могли быть поняты правильно, но реализация была ошибочной. Например:
- Ошибки, вызывающие некорректное поведение;
- Низкая производительность, делающая ПО непригодным;
- Уязвимости безопасности, подвергающие пользователей риску;
- Хрупкая архитектура, которая затрудняет обслуживание или расширение системы;
- Код настолько сложный или запутанный, что никто не может безопасно его изменить.
Про эти неудачи мы чаще всего говорим. Проверки кода, автоматизированное тестирование, статический анализ и конвейеры CI/CD, существуют в первую очередь для того, чтобы выявлять и предотвращать подобные неудачи.
2. Создание неправильного продукта
Техническое исполнение может быть безупречным, но ПО не решает нужную проблему. Продукт компилируется, запускается и может работать без проблем. Но есть признаки того, что вы создали не то, что нужно:
- Решает проблему, с которой на самом деле никто не сталкивается;
- Решает проблему, которая никому на самом деле не важна;
- Решает вчерашнюю проблему, а не сегодняшнюю;
- Предоставляет функции, которые запрашивали пользователи, но не то, что им действительно было нужно;
- Делает неверные предположения о том, как должно быть реализовано решение.
Это более тонкий и часто более дорогостоящий случай. Прекрасно разработанное, безошибочное и производительное приложение может не приносить никакой пользы, потому что оно изначально решает не ту проблему. Все усилия потрачены впустую.
Вся концепция agile-разработки, методология бережливого стартапа и такие практики, как маппинг пользовательских историй и постоянная обратная связь с клиентами, существуют в основном для борьбы с этим вторым типом ошибок. И, к сожалению, автоматизировать это не так просто. Нет компилятора, набора модульных тестов или линтера, которые бы сказали, что ваше ПО соответствует тому, что хотел клиент. Такие практики, как разработка через приёмочные тесты (ATDD), безусловно, могут помочь, но они, как правило, требуют поддержки и усилий, выходящих далеко за рамки команды разработчиков.
Почему это различие важно
Неправильная разработка часто является следствием индивидуальных навыков или, возможно, проблем с процессом в команде разработчиков. Эти проблемы часто легко обнаружить, и поэтому во многих случаях их можно относительно быстро устранить. При достаточно хорошо продуманном процессе даже джуны могут вносить свой вклад в приложение с минимальным риском того, что очевидные технические ошибки пройдут проверку, тесты и в итоге попадут в производство.
Более опасная ошибка — успешный выпуск чего-то, что не нужно. А иногда и нежелательно. Это может создать у команды разработчиков ложное чувство успеха, которое затем приводит к ещё большему разочарованию, когда им приходится откатывать изменения или вносить серьёзные обновления. Почти всегда это ошибка в коммуникации, а не в навыках программистов, и усилия, необходимые для её исправления, обычно более масштабны, постоянны (нельзя просто добавить ещё один этап сборки) и, вероятно, затронут несколько команд внутри организации. И Scrum, и XP предполагают наличие в команде разработчиков эксперта в предметной области, представляющего заказчика, но организации редко нанимают такого специалиста. Чаще это делается кем-то не связанным с командой разработчиков, кому отводится дополнительная роль «владельца продукта» или «эксперта в предметной области», чтобы разработчики могли обращаться к нему с вопросами и, возможно, периодически встречаться, и его вряд ли можно считать полноценным членом команды.
Продолжение следует…
Источник: https://ardalis.com/how-software-developers-fail/
Как Проваливаются Разработчики ПО. Начало
«Разработчики ПО терпят неудачу двумя способами: они либо делают продукт не так, либо делают не тот продукт».
Эти два вида неудачи стоит рассматривать независимо друг от друга, т.к. у них разные первопричины и последствия. И ИИ-агенты сталкиваются с теми же проблемами, но могут делать и то, и другое гораздо быстрее людей.
1. Неправильная разработка продукта
Техническое исполнение неверное. Требования могли быть поняты правильно, но реализация была ошибочной. Например:
- Ошибки, вызывающие некорректное поведение;
- Низкая производительность, делающая ПО непригодным;
- Уязвимости безопасности, подвергающие пользователей риску;
- Хрупкая архитектура, которая затрудняет обслуживание или расширение системы;
- Код настолько сложный или запутанный, что никто не может безопасно его изменить.
Про эти неудачи мы чаще всего говорим. Проверки кода, автоматизированное тестирование, статический анализ и конвейеры CI/CD, существуют в первую очередь для того, чтобы выявлять и предотвращать подобные неудачи.
2. Создание неправильного продукта
Техническое исполнение может быть безупречным, но ПО не решает нужную проблему. Продукт компилируется, запускается и может работать без проблем. Но есть признаки того, что вы создали не то, что нужно:
- Решает проблему, с которой на самом деле никто не сталкивается;
- Решает проблему, которая никому на самом деле не важна;
- Решает вчерашнюю проблему, а не сегодняшнюю;
- Предоставляет функции, которые запрашивали пользователи, но не то, что им действительно было нужно;
- Делает неверные предположения о том, как должно быть реализовано решение.
Это более тонкий и часто более дорогостоящий случай. Прекрасно разработанное, безошибочное и производительное приложение может не приносить никакой пользы, потому что оно изначально решает не ту проблему. Все усилия потрачены впустую.
Вся концепция agile-разработки, методология бережливого стартапа и такие практики, как маппинг пользовательских историй и постоянная обратная связь с клиентами, существуют в основном для борьбы с этим вторым типом ошибок. И, к сожалению, автоматизировать это не так просто. Нет компилятора, набора модульных тестов или линтера, которые бы сказали, что ваше ПО соответствует тому, что хотел клиент. Такие практики, как разработка через приёмочные тесты (ATDD), безусловно, могут помочь, но они, как правило, требуют поддержки и усилий, выходящих далеко за рамки команды разработчиков.
Почему это различие важно
Неправильная разработка часто является следствием индивидуальных навыков или, возможно, проблем с процессом в команде разработчиков. Эти проблемы часто легко обнаружить, и поэтому во многих случаях их можно относительно быстро устранить. При достаточно хорошо продуманном процессе даже джуны могут вносить свой вклад в приложение с минимальным риском того, что очевидные технические ошибки пройдут проверку, тесты и в итоге попадут в производство.
Более опасная ошибка — успешный выпуск чего-то, что не нужно. А иногда и нежелательно. Это может создать у команды разработчиков ложное чувство успеха, которое затем приводит к ещё большему разочарованию, когда им приходится откатывать изменения или вносить серьёзные обновления. Почти всегда это ошибка в коммуникации, а не в навыках программистов, и усилия, необходимые для её исправления, обычно более масштабны, постоянны (нельзя просто добавить ещё один этап сборки) и, вероятно, затронут несколько команд внутри организации. И Scrum, и XP предполагают наличие в команде разработчиков эксперта в предметной области, представляющего заказчика, но организации редко нанимают такого специалиста. Чаще это делается кем-то не связанным с командой разработчиков, кому отводится дополнительная роль «владельца продукта» или «эксперта в предметной области», чтобы разработчики могли обращаться к нему с вопросами и, возможно, периодически встречаться, и его вряд ли можно считать полноценным членом команды.
Продолжение следует…
Источник: https://ardalis.com/how-software-developers-fail/
👍6👎1
День 2648. #ProjectManagement
Как Проваливаются Разработчики ПО. Продолжение
Начало
Эпоха агентской разработки
ИИ-агенты меняют подход к разработке. Они позволяют писать, тестировать, рефакторить и развёртывать код с минимальным участием человека. Перспективы огромны: значительное повышение продуктивности разработчиков, снижение трудозатрат, ускорение итераций. Больше кода быстрее. Но ИИ-агенты не меняют существующие виды проблем, они их усиливают.
Агенты хорошо умеют создавать вещи неправильно
ИИ-агенты могут быстро генерировать большие объёмы неверного кода:
- Вносить скрытые уязвимости безопасности, которые трудно обнаружить при проверке кода;
- Писать код, который выглядит корректно, но имеет ошибки в крайних случаях;
- Исполнять заявленные требования, игнорируя подразумеваемые ограничения;
- Уверенно выдавать некорректные результаты («галлюцинации»).
Преимущество ИИ-агентов в скорости означает, что если контроль качества отсутствует, вы можете накопить гораздо больше технического долга и гораздо больше ошибок за то же время. Как никогда необходимы тесты, проверка кода (человеческая и автоматизированная) и надёжные конвейеры CI/CD. Быстрая поставка — это преимущество только в том случае, если то, что вы выпускаете, работает.
Многие команды, оценивая, как и в какой степени ИИ-агенты вписываются в их модели разработки, занимаются добавлением защитных механизмов для предотвращения перечисленных выше проблем. Добавляют больше тестов. Добавляют навыки и инструкции, указывающие агенту, что код должен компилироваться, а тесты должны проходить. Создают отдельных агентов для написания кода, тестирования, проверки и многого другого. Многие из этих усилий могут быть эффективными, хотя часто ценой гораздо больших затрат на токены.
Агенты хорошо умеют создавать не то, что нужно
Тут начинаются настоящие опасности. ИИ-агенты оптимизированы для выполнения инструкций. Они будут создавать всё, что вы попросите, — быстро и уверенно. Если вы дадите агенту краткое, плохое или несогласованное ТЗ, он выполнит его с поразительной тщательностью. Он может не возражать и не задавать уточняющих вопросов (если только вы не предусмотрели это в рабочем процессе). Он не заметит, что запрошенная функция противоречит уже существующей. Не спросит, действительно ли пользователи этого хотят. Иногда даже не заметит, существует ли уже запрошенная вами функция, а создаст другую, похожую. ИИ-агент, получив расплывчатую или неверную спецификацию, создаст расплывчатый или неверный продукт, просто быстрее, чем это сделал бы человек-разработчик.
Поэтому навыки, помогающие командам создавать правильный продукт, важны как никогда:
1. Чёткие требования и пользовательские истории. Большинство агентов созданы для того, чтобы продолжать работу, пока не почувствуют, что решили проблему. Если у них нет всех деталей, они будут гадать. Так же, как часто делают люди, но без человеческого суждения и с гораздо большей скоростью.
2. Постоянная обратная связь от заинтересованных сторон. Агенты не могут присутствовать на митингах. Людям по-прежнему необходимо собирать и анализировать обратную связь и корректировать направление.
3. Экспертные знания в предметной области. Понимание того, почему необходима та или иная функция, помогает выявлять несоответствия до того, как они будут заложены в тысячи строк сгенерированного кода.
4. Продуктовое мышление. Способность задавать вопрос «Стоит ли вообще это делать?» — это (сегодня) уникальный человеческий навык, и его ценность постоянно растёт.
Окончание следует…
Источник: https://ardalis.com/how-software-developers-fail/
Как Проваливаются Разработчики ПО. Продолжение
Начало
Эпоха агентской разработки
ИИ-агенты меняют подход к разработке. Они позволяют писать, тестировать, рефакторить и развёртывать код с минимальным участием человека. Перспективы огромны: значительное повышение продуктивности разработчиков, снижение трудозатрат, ускорение итераций. Больше кода быстрее. Но ИИ-агенты не меняют существующие виды проблем, они их усиливают.
Агенты хорошо умеют создавать вещи неправильно
ИИ-агенты могут быстро генерировать большие объёмы неверного кода:
- Вносить скрытые уязвимости безопасности, которые трудно обнаружить при проверке кода;
- Писать код, который выглядит корректно, но имеет ошибки в крайних случаях;
- Исполнять заявленные требования, игнорируя подразумеваемые ограничения;
- Уверенно выдавать некорректные результаты («галлюцинации»).
Преимущество ИИ-агентов в скорости означает, что если контроль качества отсутствует, вы можете накопить гораздо больше технического долга и гораздо больше ошибок за то же время. Как никогда необходимы тесты, проверка кода (человеческая и автоматизированная) и надёжные конвейеры CI/CD. Быстрая поставка — это преимущество только в том случае, если то, что вы выпускаете, работает.
Многие команды, оценивая, как и в какой степени ИИ-агенты вписываются в их модели разработки, занимаются добавлением защитных механизмов для предотвращения перечисленных выше проблем. Добавляют больше тестов. Добавляют навыки и инструкции, указывающие агенту, что код должен компилироваться, а тесты должны проходить. Создают отдельных агентов для написания кода, тестирования, проверки и многого другого. Многие из этих усилий могут быть эффективными, хотя часто ценой гораздо больших затрат на токены.
Агенты хорошо умеют создавать не то, что нужно
Тут начинаются настоящие опасности. ИИ-агенты оптимизированы для выполнения инструкций. Они будут создавать всё, что вы попросите, — быстро и уверенно. Если вы дадите агенту краткое, плохое или несогласованное ТЗ, он выполнит его с поразительной тщательностью. Он может не возражать и не задавать уточняющих вопросов (если только вы не предусмотрели это в рабочем процессе). Он не заметит, что запрошенная функция противоречит уже существующей. Не спросит, действительно ли пользователи этого хотят. Иногда даже не заметит, существует ли уже запрошенная вами функция, а создаст другую, похожую. ИИ-агент, получив расплывчатую или неверную спецификацию, создаст расплывчатый или неверный продукт, просто быстрее, чем это сделал бы человек-разработчик.
Поэтому навыки, помогающие командам создавать правильный продукт, важны как никогда:
1. Чёткие требования и пользовательские истории. Большинство агентов созданы для того, чтобы продолжать работу, пока не почувствуют, что решили проблему. Если у них нет всех деталей, они будут гадать. Так же, как часто делают люди, но без человеческого суждения и с гораздо большей скоростью.
2. Постоянная обратная связь от заинтересованных сторон. Агенты не могут присутствовать на митингах. Людям по-прежнему необходимо собирать и анализировать обратную связь и корректировать направление.
3. Экспертные знания в предметной области. Понимание того, почему необходима та или иная функция, помогает выявлять несоответствия до того, как они будут заложены в тысячи строк сгенерированного кода.
4. Продуктовое мышление. Способность задавать вопрос «Стоит ли вообще это делать?» — это (сегодня) уникальный человеческий навык, и его ценность постоянно растёт.
Окончание следует…
Источник: https://ardalis.com/how-software-developers-fail/
👍3👎1
День 2649. #ProjectManagement
Как Проваливаются Разработчики ПО. Окончание
Начало
Продолжение
Эффект накопления
Стоимость создания неправильного продукта людьми ограничена скоростью человека. Команда за спринт может создать 10-15 функций. С ИИ-агентами та же команда теперь может создавать 10-15 функций в день. Если эти функции неверны, потери — и количество необходимых исправлений — кратно увеличиваются. Хуже того, большая кодовая база, полная неправильных функций, создает накопительную сложность: будущим агентам (и людям) придётся обходить все ошибки, которые были допущены. Агенты отлично следуют существующим шаблонам: большая кодовая база, полная неправильных функций, будет использована в качестве модели для следующей функции. Преимущество мощности ИИ-агентов делает их опасными, когда они делают не то.
Что это значит для команд
Разработка с использованием агентов не отменяет необходимости в передовых инженерных практиках — она повышает их значимость. Все те факторы, которые повышали качество результатов для разработчиков-людей, делают то же самое для ИИ-агентов.
1. Вкладывайте значительные усилия в требования и спецификации. Чем яснее и точнее входные данные для ИИ-агентов, тем лучше результаты. Расплывчатые требования, которые разработчик-человек мог бы разумно интерпретировать, будут реализованы агентом буквально — или, что ещё хуже, изобретательно.
2. Автоматизируйте контрольные точки качества. Код, сгенерированный ИИ, нуждается в автоматизированных тестах, проверке синтаксиса, сканировании безопасности и других проверках качества. Эти контрольные точки становятся основной защитой от ошибок при масштабировании. Их также гораздо проще создать с помощью ИИ-агентов, поэтому важно настроить их с самого начала.
3. Держите людей в курсе решений по продукту. Агенты могут ускорить выполнение, но они не могут заменить суждение о том, что нужно создавать. Менеджеры по продуктам, архитекторы и старшие разработчики должны активно участвовать в определении и проверке направления развития.
4. Часто проводите проверки и валидацию. Короткие циклы обратной связи особенно важны при работе с агентами. Настройте процесс таким образом, чтобы он развивался небольшими итерациями с частыми этапами проверки человеком, чтобы гарантировать, что разработка идёт по плану.
5. Измеряйте результаты, а не только объём. В случае с ИИ-агентами возникает соблазн измерить объём выпущенного кода. Но важно то, получают ли пользователи выгоду. Отслеживайте использование, удовлетворённость пользователей и бизнес-результаты наряду с показателями скорости.
6. Оптимизируйте последующие процессы. Сегодня ИИ-агенты могут создавать код в десять раз быстрее людей. Но создание кода не было узким местом раньше, и уж точно не является им сейчас. Ускорение не являющихся узкими местами процессов в системе приводит лишь к увеличению потерь и замедлению общей доставки. Прежде чем натравить ИИ-агентов на весь ваш бэклог, убедитесь, что вы создали контрольные точки качества, автоматические проверки развёртывания, тестовые среды, где новые функции могут быть оценены и утверждены людьми, и т.д.
Итого
Разработчики и команды, которые преуспеют в эпоху ИИ-агентов, будут не просто теми, кто внедряет агентов раньше всех или наиболее агрессивно. Они будут теми, кто сочетает скорость ИИ с рассудительностью, знаниями в предметной области и ориентацией на клиента, что гарантирует создание правильного продукта правильным способом.
Быстрое движение имеет значение только в том случае, если вы движетесь в правильном направлении. Как гласит классическая цитата: «Мы заблудились, зато мы всех опережаем!»
Источник: https://ardalis.com/how-software-developers-fail/
Как Проваливаются Разработчики ПО. Окончание
Начало
Продолжение
Эффект накопления
Стоимость создания неправильного продукта людьми ограничена скоростью человека. Команда за спринт может создать 10-15 функций. С ИИ-агентами та же команда теперь может создавать 10-15 функций в день. Если эти функции неверны, потери — и количество необходимых исправлений — кратно увеличиваются. Хуже того, большая кодовая база, полная неправильных функций, создает накопительную сложность: будущим агентам (и людям) придётся обходить все ошибки, которые были допущены. Агенты отлично следуют существующим шаблонам: большая кодовая база, полная неправильных функций, будет использована в качестве модели для следующей функции. Преимущество мощности ИИ-агентов делает их опасными, когда они делают не то.
Что это значит для команд
Разработка с использованием агентов не отменяет необходимости в передовых инженерных практиках — она повышает их значимость. Все те факторы, которые повышали качество результатов для разработчиков-людей, делают то же самое для ИИ-агентов.
1. Вкладывайте значительные усилия в требования и спецификации. Чем яснее и точнее входные данные для ИИ-агентов, тем лучше результаты. Расплывчатые требования, которые разработчик-человек мог бы разумно интерпретировать, будут реализованы агентом буквально — или, что ещё хуже, изобретательно.
2. Автоматизируйте контрольные точки качества. Код, сгенерированный ИИ, нуждается в автоматизированных тестах, проверке синтаксиса, сканировании безопасности и других проверках качества. Эти контрольные точки становятся основной защитой от ошибок при масштабировании. Их также гораздо проще создать с помощью ИИ-агентов, поэтому важно настроить их с самого начала.
3. Держите людей в курсе решений по продукту. Агенты могут ускорить выполнение, но они не могут заменить суждение о том, что нужно создавать. Менеджеры по продуктам, архитекторы и старшие разработчики должны активно участвовать в определении и проверке направления развития.
4. Часто проводите проверки и валидацию. Короткие циклы обратной связи особенно важны при работе с агентами. Настройте процесс таким образом, чтобы он развивался небольшими итерациями с частыми этапами проверки человеком, чтобы гарантировать, что разработка идёт по плану.
5. Измеряйте результаты, а не только объём. В случае с ИИ-агентами возникает соблазн измерить объём выпущенного кода. Но важно то, получают ли пользователи выгоду. Отслеживайте использование, удовлетворённость пользователей и бизнес-результаты наряду с показателями скорости.
6. Оптимизируйте последующие процессы. Сегодня ИИ-агенты могут создавать код в десять раз быстрее людей. Но создание кода не было узким местом раньше, и уж точно не является им сейчас. Ускорение не являющихся узкими местами процессов в системе приводит лишь к увеличению потерь и замедлению общей доставки. Прежде чем натравить ИИ-агентов на весь ваш бэклог, убедитесь, что вы создали контрольные точки качества, автоматические проверки развёртывания, тестовые среды, где новые функции могут быть оценены и утверждены людьми, и т.д.
Итого
Разработчики и команды, которые преуспеют в эпоху ИИ-агентов, будут не просто теми, кто внедряет агентов раньше всех или наиболее агрессивно. Они будут теми, кто сочетает скорость ИИ с рассудительностью, знаниями в предметной области и ориентацией на клиента, что гарантирует создание правильного продукта правильным способом.
Быстрое движение имеет значение только в том случае, если вы движетесь в правильном направлении. Как гласит классическая цитата: «Мы заблудились, зато мы всех опережаем!»
Источник: https://ardalis.com/how-software-developers-fail/
👍7👎1
День 2650. #ВопросыНаСобеседовании
Марк Прайс предложил свой набор из 60 вопросов (как технических, так и на софт-скилы), которые могут задать на собеседовании.
32. Синтаксис Razor
«Расскажите, что такое Razor и как он используется в приложениях ASP.NET Core? Приведите пример».
Хороший ответ
Razor — это синтаксис разметки, который позволяет встраивать код C# в HTML-документы для динамической генерации HTML-контента на сервере перед его отправкой клиенту. Он используется в основном в представлениях ASP.NET Core MVC, Razor Pages и веб-приложениях Blazor для создания динамических веб-страниц.
Блоки кода в Razor начинаются с символа @, который помогает компилятору отличать код C# от HTML. Это позволяет беспрепятственно интегрировать серверную логику в структурированный HTML-файл, расширяя возможности рендеринга веб-страниц на основе динамических данных.
В качестве примера синтаксиса Razor в представлении ASP.NET Core MVC рассмотрим простую модель, представляющую продукт:
В следующем представлении показано, как отобразить список продуктов:
В этом примере синтаксис Razor используется для итерации по коллекции объектов Product, переданных в представление из контроллера. Он динамически генерирует строки таблицы (
Преимущества использования Razor включают:
- Повышение производительности: Razor снижает сложность написания и поддержки динамических веб-страниц, позволяя разработчикам писать код C# непосредственно в представлении.
- Строгая типизация: Используя C# в представлении, Razor поддерживает IntelliSense и проверку кода во время компиляции, уменьшая количество ошибок во время выполнения.
- Чёткое разделение: Razor помогает поддерживать чёткое разделение задач между логикой пользовательского интерфейса и логикой бэкэнда, придерживаясь паттерна MVC.
Часто встречающийся неверный ответ
«Синтаксис Razor — это просто использование символа @ для написания любого кода C# непосредственно в HTML. Можно выполнять любую бизнес-логику в представлении, чтобы манипулировать данными так, как вам нужно».
Почему это неправильно
- Неправильное использование Razor для бизнес-логики: Этот ответ предполагает ненадлежащее использование представлений Razor для выполнения бизнес-логики, что нарушает принцип разделения ответственности в MVC. Представления Razor предназначены для обработки логики представления, а не бизнес-логики.
- Потенциальные проблемы с избыточностью и поддержкой: Встраивание сложной логики C# в представления Razor может привести к избыточному, трудно поддерживаемому коду. Это затрудняет чтение и управление представлением, особенно для других разработчиков или при возвращении к коду через некоторое время.
- Проблемы с производительностью: Выполнение сложной логики в представлении может привести к проблемам с производительностью, поскольку она может обрабатываться для каждого запроса, а не более эффективно обрабатываться на уровне контроллера или сервиса.
Эта ошибка обычно возникает из-за непонимания ролей в паттерне MVC или из-за опыта работы с фреймворками веб-разработки, которые нечетко разделяют бизнес-логику и логику представления.
Источник: https://github.com/markjprice/tools-skills-net8/blob/main/docs/interview-qa/readme.md
Марк Прайс предложил свой набор из 60 вопросов (как технических, так и на софт-скилы), которые могут задать на собеседовании.
32. Синтаксис Razor
«Расскажите, что такое Razor и как он используется в приложениях ASP.NET Core? Приведите пример».
Хороший ответ
Razor — это синтаксис разметки, который позволяет встраивать код C# в HTML-документы для динамической генерации HTML-контента на сервере перед его отправкой клиенту. Он используется в основном в представлениях ASP.NET Core MVC, Razor Pages и веб-приложениях Blazor для создания динамических веб-страниц.
Блоки кода в Razor начинаются с символа @, который помогает компилятору отличать код C# от HTML. Это позволяет беспрепятственно интегрировать серверную логику в структурированный HTML-файл, расширяя возможности рендеринга веб-страниц на основе динамических данных.
В качестве примера синтаксиса Razor в представлении ASP.NET Core MVC рассмотрим простую модель, представляющую продукт:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
В следующем представлении показано, как отобразить список продуктов:
@model IEnumerable<Product>
<h2>Список Продуктов</h2>
<table>
<thead>
<tr>
<th>Название</th>
<th>Цена</th>
</tr>
</thead>
<tbody>
@foreach (var p in Model)
{
<tr>
<td>@p.Name</td>
@* Денежный формат *@
<td>@p.Price.ToString("C")</td>
</tr>
}
</tbody>
</table>
В этом примере синтаксис Razor используется для итерации по коллекции объектов Product, переданных в представление из контроллера. Он динамически генерирует строки таблицы (
<tr>) для каждого продукта с его названием и ценой. Символ @ используется для вставки кода C# в HTML для итерации по списку и отображения данных.Преимущества использования Razor включают:
- Повышение производительности: Razor снижает сложность написания и поддержки динамических веб-страниц, позволяя разработчикам писать код C# непосредственно в представлении.
- Строгая типизация: Используя C# в представлении, Razor поддерживает IntelliSense и проверку кода во время компиляции, уменьшая количество ошибок во время выполнения.
- Чёткое разделение: Razor помогает поддерживать чёткое разделение задач между логикой пользовательского интерфейса и логикой бэкэнда, придерживаясь паттерна MVC.
Часто встречающийся неверный ответ
«Синтаксис Razor — это просто использование символа @ для написания любого кода C# непосредственно в HTML. Можно выполнять любую бизнес-логику в представлении, чтобы манипулировать данными так, как вам нужно».
Почему это неправильно
- Неправильное использование Razor для бизнес-логики: Этот ответ предполагает ненадлежащее использование представлений Razor для выполнения бизнес-логики, что нарушает принцип разделения ответственности в MVC. Представления Razor предназначены для обработки логики представления, а не бизнес-логики.
- Потенциальные проблемы с избыточностью и поддержкой: Встраивание сложной логики C# в представления Razor может привести к избыточному, трудно поддерживаемому коду. Это затрудняет чтение и управление представлением, особенно для других разработчиков или при возвращении к коду через некоторое время.
- Проблемы с производительностью: Выполнение сложной логики в представлении может привести к проблемам с производительностью, поскольку она может обрабатываться для каждого запроса, а не более эффективно обрабатываться на уровне контроллера или сервиса.
Эта ошибка обычно возникает из-за непонимания ролей в паттерне MVC или из-за опыта работы с фреймворками веб-разработки, которые нечетко разделяют бизнес-логику и логику представления.
Источник: https://github.com/markjprice/tools-skills-net8/blob/main/docs/interview-qa/readme.md
👎7👍2
День 2651. #ЧтоНовенького
VSTest удаляет зависимость от Newtonsoft.Json
Начиная с .NET 11 Preview 4 и Visual Studio 18.8, VSTest, платформа, на которой работают dotnet test и Test Explorer, больше не будет зависеть от Newtonsoft.Json. Теперь будет использоваться System.Text.Json в .NET и JSONite в .NET Framework. Большинству проектов никаких действий не требуется. Небольшое количество проектов может столкнуться с ошибкой сборки или тестирования и решить её добавлением одной строки PackageReference.
Зачем?
VSTest годами поставлялся с Newtonsoft.Json в составе .NET SDK и Visual Studio. Все версии Newtonsoft.Json ниже 13.0.0 теперь помечены как уязвимые на NuGet.org, и наличие этой зависимости делает тестовую платформу уязвимой в компоненте, который ей больше не нужен. Удаление является частью более масштабной работы по удалению Newtonsoft.Json из .NET SDK.
Что не меняется?
- Формат передачи VSTest. Сообщения сериализуются одинаково независимо от того, используется ли Newtonsoft.Json, System.Text.Json или JSONite.
- Старые тестовые хосты остаются совместимыми с обновлённой платформой, и наоборот.
- Производительность сериализации остается прежней или улучшается.
Кого это НЕ затронет?
Большинство тестовых проектов:
- Проекты, которые не используют Newtonsoft.Json.
- Проекты, которые ссылаются на Newtonsoft.Json в виде обычной ссылки PackageReference.
- Проекты xUnit и NUnit, работающие на .NET или использующие AppDomains. Для них уже требовалась явная ссылка.
Кого это затронет и как это исправить
Каждая из перечисленных ниже ошибок не является скрытой, сообщается в ходе выполнения теста и передаётся в TRX и представления тестов Azure DevOps / GitHub.
1. Ошибка сборки: отсутствует ссылка на Newtonsoft.Json
Если тестовый проект использует типы Newtonsoft.Json (например, JObject, JsonConvert) без ссылки на этот пакет, ранее он компилировался только потому, что Newtonsoft.Json просачивался через VSTest. После обновления это будет не так.
Исправление: добавьте пакет.
2. Ошибка выполнения: FileNotFoundException для Newtonsoft.Json
Проекты, которые ссылаются на Newtonsoft.Json, но не содержат ресурс времени выполнения — например:
Предполагалось, что копия библиотеки из VSTest будет присутствовать во время тестирования. После этого обновления запуск теста завершится с ошибкой:
Исправление: уберите
3. Ошибка загрузки расширения в тестовом адаптере или сборщике данных
Адаптеры и сборщики данных, которые использовали Newtonsoft.Json, не указав его в качестве зависимости, завершатся с ошибкой во время загрузки с сообщением, подобным следующему:
В сообщении будет указано имя расширения, которое необходимо обновить, однако на данный момент о таких проблемах не сообщалось. Авторам расширений следует добавить Newtonsoft.Json в свой пакет (или отказаться от него); пользователи могут добавить Newtonsoft.Json в тестовый проект или отключить затронутое расширение до его обновления.
Изменение публичного API
VSTest предоставлял доступ к Newtonsoft.Json.Linq.JToken в одном месте своего API связи. Этот тип удаляется из публичного доступа. Он имел смысл только для кода, участвующего в протоколе VSTest, и вряд ли будет использоваться реальными пользователями, но авторам расширений следует об этом знать.
Источник: https://devblogs.microsoft.com/dotnet/vs-test-is-removing-its-newtonsoft-json-dependency/
VSTest удаляет зависимость от Newtonsoft.Json
Начиная с .NET 11 Preview 4 и Visual Studio 18.8, VSTest, платформа, на которой работают dotnet test и Test Explorer, больше не будет зависеть от Newtonsoft.Json. Теперь будет использоваться System.Text.Json в .NET и JSONite в .NET Framework. Большинству проектов никаких действий не требуется. Небольшое количество проектов может столкнуться с ошибкой сборки или тестирования и решить её добавлением одной строки PackageReference.
Зачем?
VSTest годами поставлялся с Newtonsoft.Json в составе .NET SDK и Visual Studio. Все версии Newtonsoft.Json ниже 13.0.0 теперь помечены как уязвимые на NuGet.org, и наличие этой зависимости делает тестовую платформу уязвимой в компоненте, который ей больше не нужен. Удаление является частью более масштабной работы по удалению Newtonsoft.Json из .NET SDK.
Что не меняется?
- Формат передачи VSTest. Сообщения сериализуются одинаково независимо от того, используется ли Newtonsoft.Json, System.Text.Json или JSONite.
- Старые тестовые хосты остаются совместимыми с обновлённой платформой, и наоборот.
- Производительность сериализации остается прежней или улучшается.
Кого это НЕ затронет?
Большинство тестовых проектов:
- Проекты, которые не используют Newtonsoft.Json.
- Проекты, которые ссылаются на Newtonsoft.Json в виде обычной ссылки PackageReference.
- Проекты xUnit и NUnit, работающие на .NET или использующие AppDomains. Для них уже требовалась явная ссылка.
Кого это затронет и как это исправить
Каждая из перечисленных ниже ошибок не является скрытой, сообщается в ходе выполнения теста и передаётся в TRX и представления тестов Azure DevOps / GitHub.
1. Ошибка сборки: отсутствует ссылка на Newtonsoft.Json
Если тестовый проект использует типы Newtonsoft.Json (например, JObject, JsonConvert) без ссылки на этот пакет, ранее он компилировался только потому, что Newtonsoft.Json просачивался через VSTest. После обновления это будет не так.
Исправление: добавьте пакет.
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
2. Ошибка выполнения: FileNotFoundException для Newtonsoft.Json
Проекты, которые ссылаются на Newtonsoft.Json, но не содержат ресурс времени выполнения — например:
<PackageReference Include="Newtonsoft.Json" Version="13.0.3">
<ExcludeAssets>runtime</ExcludeAssets>
</PackageReference>
Предполагалось, что копия библиотеки из VSTest будет присутствовать во время тестирования. После этого обновления запуск теста завершится с ошибкой:
System.IO.FileNotFoundException: Could not load file or assembly 'Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed'.
Исправление: уберите
<ExcludeAssets>runtime</ExcludeAssets>, либо установите Newtonsoft.Json без исключения ресурсов времени выполнения.3. Ошибка загрузки расширения в тестовом адаптере или сборщике данных
Адаптеры и сборщики данных, которые использовали Newtonsoft.Json, не указав его в качестве зависимости, завершатся с ошибкой во время загрузки с сообщением, подобным следующему:
Data collector 'SampleDataCollector' threw an exception during type loading, construction, or initialization: System.IO.FileNotFoundException: Could not load file or assembly 'Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed'.
В сообщении будет указано имя расширения, которое необходимо обновить, однако на данный момент о таких проблемах не сообщалось. Авторам расширений следует добавить Newtonsoft.Json в свой пакет (или отказаться от него); пользователи могут добавить Newtonsoft.Json в тестовый проект или отключить затронутое расширение до его обновления.
Изменение публичного API
VSTest предоставлял доступ к Newtonsoft.Json.Linq.JToken в одном месте своего API связи. Этот тип удаляется из публичного доступа. Он имел смысл только для кода, участвующего в протоколе VSTest, и вряд ли будет использоваться реальными пользователями, но авторам расширений следует об этом знать.
Источник: https://devblogs.microsoft.com/dotnet/vs-test-is-removing-its-newtonsoft-json-dependency/
👍3
День 2652. #МоиИнструменты #PG
Инструменты Оптимизации Запросов в PostgreSQL. Часть 8
8. QueryPie (совместная работа с SQL + оптимизация)
Что даёт: Совместная работа команды над оптимизацией запросов со встроенным анализом производительности.
Тип: Коммерческий (доступен бесплатный уровень)
Базы данных: Postgres, MySQL, Redshift, BigQuery, Snowflake
Зачем нужен
Большинство оптимизаций запросов происходит изолированно. Один человек пишет медленный запрос, другой в итоге замечает и исправляет его. QueryPie делает оптимизацию совместной — запросы передаются, показатели производительности видны команде, а улучшения документируются.
Как работает
Пишете запрос в IDE QueryPie -> Автоматически запускается EXPLAIN ANALYZE -> Отображаются показатели производительности -> Делитесь запросом с командой по ссылке -> Члены команды предлагают варианты оптимизации -> A/B-сравнение версий запроса -> Лучшая версия продвигается в прод.
Пример рабочего процесса
1. Аналитик данных пишет запрос (QueryPie IDE)
2. Вывод QueryPie:
3. Разработчик нажимает "Предложить оптимизацию". ИИ QueryPie предлагает:
4. Новые метрики:
5. Показывается сравнение результатов.
6. При нажатии кнопки «Принять оптимизацию» исходный запрос помечается как устаревший, команда уведомляется об улучшении.
Когда использовать
- Несколько человек пишут SQL-запросы;
- Требуется совместная оптимизация;
- Необходимо версионирование запросов;
- Предпочитаете веб-IDE локальным инструментам.
Когда отказаться
- Разработчик-одиночка (функции совместной работы не используются);
- Довольны текущей IDE (pgAdmin, DBeaver и т. д.);
- Очень ограниченный бюджет ($15-50 на пользователя в месяц).
Скрытая функция
Автоматическое обнаружение регрессии производительности запросов. QueryPie отслеживает каждое выполнение запроса и может предоставлять динамику производительности запроса во времени и рекомендации по улучшению.
С осторожностью
QueryPie хранит результаты запросов. Соображения конфиденциальности:
- Запросы выполняются через прокси QueryPie;
- Результаты кэшируются для обмена;
- Может содержать конфиденциальные данные.
Конфигурация:
- Установить политику хранения данных (по умолчанию 7 дней);
- Исключить столбцы с персональными данными из кэширования;
- Использовать локальное развёртывание для конфиденциальных данных;
- Перед развёртыванием командой проверить политики безопасности.
Источник: https://medium.com/@reliabledataengineering/15-sql-optimization-tools-that-make-queries-10x-faster-8629ac451d97
Инструменты Оптимизации Запросов в PostgreSQL. Часть 8
8. QueryPie (совместная работа с SQL + оптимизация)
Что даёт: Совместная работа команды над оптимизацией запросов со встроенным анализом производительности.
Тип: Коммерческий (доступен бесплатный уровень)
Базы данных: Postgres, MySQL, Redshift, BigQuery, Snowflake
Зачем нужен
Большинство оптимизаций запросов происходит изолированно. Один человек пишет медленный запрос, другой в итоге замечает и исправляет его. QueryPie делает оптимизацию совместной — запросы передаются, показатели производительности видны команде, а улучшения документируются.
Как работает
Пишете запрос в IDE QueryPie -> Автоматически запускается EXPLAIN ANALYZE -> Отображаются показатели производительности -> Делитесь запросом с командой по ссылке -> Члены команды предлагают варианты оптимизации -> A/B-сравнение версий запроса -> Лучшая версия продвигается в прод.
Пример рабочего процесса
1. Аналитик данных пишет запрос (QueryPie IDE)
SELECT
c.customer_name,
SUM(o.total) as revenue
FROM customers c
LEFT JOIN orders o ON c.id = o.customer_id
WHERE c.country = 'US'
GROUP BY c.customer_name
ORDER BY revenue DESC
LIMIT 100;
2. Вывод QueryPie:
Execution time: 23.4s
Rows scanned: 5.2M
Cost: $0.45 (Вымышленная валюта)
Warning: LEFT JOIN inefficient (NULL handling overhead)
3. Разработчик нажимает "Предложить оптимизацию". ИИ QueryPie предлагает:
SELECT
c.customer_name,
SUM(o.total) as revenue
FROM customers c
INNER JOIN orders o ON c.id = o.customer_id -- Добавить INNER
WHERE c.country = 'US'
AND o.total IS NOT NULL -- Добавить фильтр
GROUP BY c.customer_name
ORDER BY revenue DESC
LIMIT 100;
4. Новые метрики:
Execution time: 1.2s (19x faster)
Rows scanned: 234K (22x less)
Cost: $0.02 (22x cheaper)
5. Показывается сравнение результатов.
6. При нажатии кнопки «Принять оптимизацию» исходный запрос помечается как устаревший, команда уведомляется об улучшении.
Когда использовать
- Несколько человек пишут SQL-запросы;
- Требуется совместная оптимизация;
- Необходимо версионирование запросов;
- Предпочитаете веб-IDE локальным инструментам.
Когда отказаться
- Разработчик-одиночка (функции совместной работы не используются);
- Довольны текущей IDE (pgAdmin, DBeaver и т. д.);
- Очень ограниченный бюджет ($15-50 на пользователя в месяц).
Скрытая функция
Автоматическое обнаружение регрессии производительности запросов. QueryPie отслеживает каждое выполнение запроса и может предоставлять динамику производительности запроса во времени и рекомендации по улучшению.
С осторожностью
QueryPie хранит результаты запросов. Соображения конфиденциальности:
- Запросы выполняются через прокси QueryPie;
- Результаты кэшируются для обмена;
- Может содержать конфиденциальные данные.
Конфигурация:
- Установить политику хранения данных (по умолчанию 7 дней);
- Исключить столбцы с персональными данными из кэширования;
- Использовать локальное развёртывание для конфиденциальных данных;
- Перед развёртыванием командой проверить политики безопасности.
Источник: https://medium.com/@reliabledataengineering/15-sql-optimization-tools-that-make-queries-10x-faster-8629ac451d97
👍3
День 2653. #Оффтоп
История Архитектур Приложений в .NET. Начало
Ранние годы
Классический ASP / «Спагетти-код» (конец 1990-х). До появления .NET веб-приложения Microsoft создавались с помощью классического ASP — скриптового языка VBScript, смешанного с HTML. Реальной архитектуры не было; бизнес-логика, доступ к данным и представления были переплетены между собой. От этого отказались, потому что это было неподдерживаемо, нетестируемо и немасштабируемо.
Web Forms (2002–~2012). ASP.NET Web Forms был первым крупным веб-фреймворком .NET от Microsoft. Он пытался сделать веб-разработку похожей на разработку настольных приложений, абстрагируя HTTP с помощью модели, основанной на состоянии и событиях (ViewState, postbacks, серверные элементы управления). Его заменили, потому что абстракция сильно «протекала». Она создавала раздутый HTML, делала модульное тестирование практически невозможным, противоречила тому, как на самом деле работает веб, и давала разработчикам очень мало контроля над отображаемым результатом. К тому времени, когда появились jQuery, а затем и фронтенд-фреймворки, Web Forms казался архаичным.
Основополагающие шаблоны (по-прежнему актуальны, но эволюционировали)
Многоуровневая/трёхуровневая архитектура. Классический многоуровневый подход: представление → бизнес-логика → доступ к данным. Это был основной принцип работы корпоративного .NET на протяжении многих лет. Теоретически каждый уровень мог быть развёрнут независимо. Он не устарел сам по себе, но был усовершенствован. Проблема заключалась в том, что на практике команды часто получали «анемичный» бизнес-слой, который просто передавал данные, и тесную связь между слоями через общие DTO или модели Entity Framework, просачивающиеся вверх.
MVC (Модель-Представление-Контроллер). ASP.NET MVC был запущен примерно в 2009 году как «противоядие» от Web Forms. Он использовал HTTP, предоставлял разработчикам контроль над HTML, позволял проводить модульное тестирование и правильно соблюдал принцип разделения ответственности. MVC по-прежнему широко используется в ASP.NET Core, хотя Razor Pages и Minimal API стали использоваться в более простых сценариях. MVC остается предпочтительным вариантом для сложных веб-приложений с множеством контроллеров и представлений.
MVVM (Модель-Представление-Модель Представления). Этот шаблон стал доминирующим в настольных приложениях WPF и Silverlight, а позже и в Xamarin. Модель Представления (ViewModel) предоставляет данные и команды, к которым представление привязывается декларативно. MVVM по-прежнему является основным шаблоном для .NET MAUI (преемника Xamarin.Forms) и WPF. Silverlight мёртв, но концепция MVVM процветает.
Сервисно-ориентированные шаблоны
WCF (Windows Communication Foundation). Представлял собой унифицированную платформу Microsoft для создания сервисно-ориентированных приложений — SOAP, REST, именованные каналы, TCP, очереди сообщений — всё в рамках одной модели программирования. Был невероятно мощным и таким же сложным. Конфигурация была печально известна своей сложностью (бесконечные XML-файлы). WCF был вытеснен, потому что отрасль перешла к легковесным REST/HTTP API, и сложность WCF не была оправдана для большинства вариантов использования. ASP.NET Web API, а позже и ASP.NET Core, заняли его место. Существует поддерживаемый сообществом проект CoreWCF для сценариев миграции, но новые проекты почти никогда не выбирают WCF.
Web API / REST ASP.NET Web API (2012), а затем и ASP.NET Core сделали создание HTTP API простым. Теперь это стандарт для взаимодействия сервисов в .NET. Минимальные API в .NET 6+ ещё больше упростили его для небольших сервисов.
gRPC. Для взаимодействия между сервисами, где важна производительность, gRPC (поддерживается нативно в ASP.NET Core) предлагает бинарную сериализацию через Protocol Buffers, потоковую передачу HTTP/2 и строгие контракты. Это современная замена WCF в сценариях взаимодействия между сервисами, где не требуется совместимость с браузерами.
Окончание следует…
Источник: https://todayamerican.medium.com/net-c-application-architecture-over-time-7218f0470a02
История Архитектур Приложений в .NET. Начало
Ранние годы
Классический ASP / «Спагетти-код» (конец 1990-х). До появления .NET веб-приложения Microsoft создавались с помощью классического ASP — скриптового языка VBScript, смешанного с HTML. Реальной архитектуры не было; бизнес-логика, доступ к данным и представления были переплетены между собой. От этого отказались, потому что это было неподдерживаемо, нетестируемо и немасштабируемо.
Web Forms (2002–~2012). ASP.NET Web Forms был первым крупным веб-фреймворком .NET от Microsoft. Он пытался сделать веб-разработку похожей на разработку настольных приложений, абстрагируя HTTP с помощью модели, основанной на состоянии и событиях (ViewState, postbacks, серверные элементы управления). Его заменили, потому что абстракция сильно «протекала». Она создавала раздутый HTML, делала модульное тестирование практически невозможным, противоречила тому, как на самом деле работает веб, и давала разработчикам очень мало контроля над отображаемым результатом. К тому времени, когда появились jQuery, а затем и фронтенд-фреймворки, Web Forms казался архаичным.
Основополагающие шаблоны (по-прежнему актуальны, но эволюционировали)
Многоуровневая/трёхуровневая архитектура. Классический многоуровневый подход: представление → бизнес-логика → доступ к данным. Это был основной принцип работы корпоративного .NET на протяжении многих лет. Теоретически каждый уровень мог быть развёрнут независимо. Он не устарел сам по себе, но был усовершенствован. Проблема заключалась в том, что на практике команды часто получали «анемичный» бизнес-слой, который просто передавал данные, и тесную связь между слоями через общие DTO или модели Entity Framework, просачивающиеся вверх.
MVC (Модель-Представление-Контроллер). ASP.NET MVC был запущен примерно в 2009 году как «противоядие» от Web Forms. Он использовал HTTP, предоставлял разработчикам контроль над HTML, позволял проводить модульное тестирование и правильно соблюдал принцип разделения ответственности. MVC по-прежнему широко используется в ASP.NET Core, хотя Razor Pages и Minimal API стали использоваться в более простых сценариях. MVC остается предпочтительным вариантом для сложных веб-приложений с множеством контроллеров и представлений.
MVVM (Модель-Представление-Модель Представления). Этот шаблон стал доминирующим в настольных приложениях WPF и Silverlight, а позже и в Xamarin. Модель Представления (ViewModel) предоставляет данные и команды, к которым представление привязывается декларативно. MVVM по-прежнему является основным шаблоном для .NET MAUI (преемника Xamarin.Forms) и WPF. Silverlight мёртв, но концепция MVVM процветает.
Сервисно-ориентированные шаблоны
WCF (Windows Communication Foundation). Представлял собой унифицированную платформу Microsoft для создания сервисно-ориентированных приложений — SOAP, REST, именованные каналы, TCP, очереди сообщений — всё в рамках одной модели программирования. Был невероятно мощным и таким же сложным. Конфигурация была печально известна своей сложностью (бесконечные XML-файлы). WCF был вытеснен, потому что отрасль перешла к легковесным REST/HTTP API, и сложность WCF не была оправдана для большинства вариантов использования. ASP.NET Web API, а позже и ASP.NET Core, заняли его место. Существует поддерживаемый сообществом проект CoreWCF для сценариев миграции, но новые проекты почти никогда не выбирают WCF.
Web API / REST ASP.NET Web API (2012), а затем и ASP.NET Core сделали создание HTTP API простым. Теперь это стандарт для взаимодействия сервисов в .NET. Минимальные API в .NET 6+ ещё больше упростили его для небольших сервисов.
gRPC. Для взаимодействия между сервисами, где важна производительность, gRPC (поддерживается нативно в ASP.NET Core) предлагает бинарную сериализацию через Protocol Buffers, потоковую передачу HTTP/2 и строгие контракты. Это современная замена WCF в сценариях взаимодействия между сервисами, где не требуется совместимость с браузерами.
Окончание следует…
Источник: https://todayamerican.medium.com/net-c-application-architecture-over-time-7218f0470a02
👍9👎1
День 2654. #Оффтоп
История Архитектур Приложений в .NET. Окончание
Начало
Современные архитектурные стили
Чистая/Луковая/Гексагональная архитектура. Это вариации одной идеи: инвертирование направления зависимостей, чтобы доменная/бизнес-логика находилась в центре, без зависимостей от инфраструктуры. Инфраструктура (БД, файловая система, внешние API) зависит от домена через абстракции (интерфейсы), а не наоборот. Это вытеснило наивный многоуровневый подход, поскольку делает бизнес-логику действительно тестируемой и заменяемой. Чистая архитектура (популяризированная Робертом Мартином и в .NET шаблоном Джейсона Тейлора) — вероятно, самая распространённая «серьёзная» архитектура для приложений .NET сегодня.
CQRS (Разделение Ответственности Команд и Запросов). Разделяет операции чтения (запросы) и записи (команды). Часто используется в сочетании с MediatR в .NET. Добавляет сложности, поэтому лучше всего подходит для областей, где шаблоны чтения и записи значительно различаются.
Источники событий (Event Sourcing). Вместо хранения текущего состояния вы храните последовательность событий, которые привели к текущему состоянию. Часто используется в сочетании с CQRS. Мощный инструмент для журналов аудита и сложных доменов, но значительно усложняет систему. Это нишевый шаблон — ценный, когда он необходим, избыточный, когда нет.
Микросервисы. Разделение приложения на независимо развёртываемые сервисы, каждый из которых владеет собственными данными. В .NET имеет сильную поддержку благодаря ASP.NET Core, Docker, Kubernetes и .NET Aspire. Микросервисы вытеснили монолиты для больших команд и сложных областей, но наблюдается заметное движение против них, признающее, что микросервисы вносят сложность распределённых систем (сбои сети, конечная согласованность, операционные накладные расходы), с которой многие команды не готовы справиться.
Модульный монолит. Это набирающая популярность «разумная золотая середина» — единая развёртываемая система, внутренне организованная в чётко ограниченные модули с ясными интерфейсами между ними. Вы получаете большинство организационных преимуществ микросервисов без проблем распределённых систем. Если позже потребуется выделить модуль в отдельный сервис, границы уже будут четко определены.
Шаблоны для настольных/клиентских приложений
Windows Forms (WinForms) — всё ещё поддерживается, все ещё используется, но в значительной степени считается устаревшим фреймворком для новой разработки. Имеет событийно-ориентированный, тесно связанный код пользовательского интерфейса.
WPF. Более современный фреймворк для настольных приложений с MVVM, привязкой данных и XAML. Всё ещё активно поддерживается и используется для сложных настольных приложений.
Xamarin → .NET MAUI — кроссплатформенное мобильное/настольное приложение. Xamarin снят с поддержки; MAUI — его преемник, использующий шаблон MVVM.
Blazor. Новейший фреймворк, позволяющий писать интерактивный веб-интерфейс на C# вместо JavaScript. Доступен в серверной (на основе SignalR) и WebAssembly версиях. Не заменяет все фронтенд-фреймворки, но привлекателен для команд, которые хотят оставаться в C#.
Итого: что на что заменено
Веб-интерфейс: Веб-формы → MVC → Razor Pages/минимальные API.
Сервисы: WCF → Web API → gRPC.
Структура проекта: Многоуровневая архитектура → Чистая архитектура.
Топология развёртывания: Монолит → Микросервисы → Модульный монолит.
Все эти переходы объединены одними и теми же несколькими факторами: тестируемость, автономность команд, гибкость развёртывания и честное признание издержек, связанных со сложностью. Каждое поколение училось на ошибках предыдущего, иногда чрезмерно корректировало свои действия, а затем занимало более сбалансированную позицию.
Источник: https://todayamerican.medium.com/net-c-application-architecture-over-time-7218f0470a02
История Архитектур Приложений в .NET. Окончание
Начало
Современные архитектурные стили
Чистая/Луковая/Гексагональная архитектура. Это вариации одной идеи: инвертирование направления зависимостей, чтобы доменная/бизнес-логика находилась в центре, без зависимостей от инфраструктуры. Инфраструктура (БД, файловая система, внешние API) зависит от домена через абстракции (интерфейсы), а не наоборот. Это вытеснило наивный многоуровневый подход, поскольку делает бизнес-логику действительно тестируемой и заменяемой. Чистая архитектура (популяризированная Робертом Мартином и в .NET шаблоном Джейсона Тейлора) — вероятно, самая распространённая «серьёзная» архитектура для приложений .NET сегодня.
CQRS (Разделение Ответственности Команд и Запросов). Разделяет операции чтения (запросы) и записи (команды). Часто используется в сочетании с MediatR в .NET. Добавляет сложности, поэтому лучше всего подходит для областей, где шаблоны чтения и записи значительно различаются.
Источники событий (Event Sourcing). Вместо хранения текущего состояния вы храните последовательность событий, которые привели к текущему состоянию. Часто используется в сочетании с CQRS. Мощный инструмент для журналов аудита и сложных доменов, но значительно усложняет систему. Это нишевый шаблон — ценный, когда он необходим, избыточный, когда нет.
Микросервисы. Разделение приложения на независимо развёртываемые сервисы, каждый из которых владеет собственными данными. В .NET имеет сильную поддержку благодаря ASP.NET Core, Docker, Kubernetes и .NET Aspire. Микросервисы вытеснили монолиты для больших команд и сложных областей, но наблюдается заметное движение против них, признающее, что микросервисы вносят сложность распределённых систем (сбои сети, конечная согласованность, операционные накладные расходы), с которой многие команды не готовы справиться.
Модульный монолит. Это набирающая популярность «разумная золотая середина» — единая развёртываемая система, внутренне организованная в чётко ограниченные модули с ясными интерфейсами между ними. Вы получаете большинство организационных преимуществ микросервисов без проблем распределённых систем. Если позже потребуется выделить модуль в отдельный сервис, границы уже будут четко определены.
Шаблоны для настольных/клиентских приложений
Windows Forms (WinForms) — всё ещё поддерживается, все ещё используется, но в значительной степени считается устаревшим фреймворком для новой разработки. Имеет событийно-ориентированный, тесно связанный код пользовательского интерфейса.
WPF. Более современный фреймворк для настольных приложений с MVVM, привязкой данных и XAML. Всё ещё активно поддерживается и используется для сложных настольных приложений.
Xamarin → .NET MAUI — кроссплатформенное мобильное/настольное приложение. Xamarin снят с поддержки; MAUI — его преемник, использующий шаблон MVVM.
Blazor. Новейший фреймворк, позволяющий писать интерактивный веб-интерфейс на C# вместо JavaScript. Доступен в серверной (на основе SignalR) и WebAssembly версиях. Не заменяет все фронтенд-фреймворки, но привлекателен для команд, которые хотят оставаться в C#.
Итого: что на что заменено
Веб-интерфейс: Веб-формы → MVC → Razor Pages/минимальные API.
Сервисы: WCF → Web API → gRPC.
Структура проекта: Многоуровневая архитектура → Чистая архитектура.
Топология развёртывания: Монолит → Микросервисы → Модульный монолит.
Все эти переходы объединены одними и теми же несколькими факторами: тестируемость, автономность команд, гибкость развёртывания и честное признание издержек, связанных со сложностью. Каждое поколение училось на ошибках предыдущего, иногда чрезмерно корректировало свои действия, а затем занимало более сбалансированную позицию.
Источник: https://todayamerican.medium.com/net-c-application-architecture-over-time-7218f0470a02
👍9👎1
День 2655. #ЧтоНовенького
Атрибут ConfigurationIgnore в .NET 11
В Microsoft.Extensions.Configuration атрибут ConfigurationKeyNameAttribute существует с .NET 6 и позволяет переименовывать ключ, к которому привязано свойство. Но официального способа указать «не привязывать это свойство вообще» никогда не было. Этот пробел наконец-то устранён в .NET 11 с помощью ConfigurationIgnoreAttribute.
Проблема
Допустим, у вас есть класс параметров, который выглядит примерно так:
DefaultFormat извлекается из DefaultFormatSection после некоторой постобработки. Его никогда не следует заполнять напрямую связывателем. Но поскольку у него есть публичные геттер и сеттер, система конфигурации пытается его связать.
Единственным обходным путём до .NET 11 было злоупотребление ConfigurationKeyNameAttribute с намеренно некорректным ключом:
Это ненадёжно, вводит в заблуждение и создаёт странный код в вашей схеме конфигурации.
Решение
.NET 11 добавляет специальный атрибут ConfigurationIgnoreAttribute в Microsoft.Extensions.Configuration. Просто добавляем атрибут к тому свойству, которое не должно быть привязано:
Ещё один распространённый сценарий
Постобработка — наиболее очевидный, но не единственный вариант использования. Ещё один классический пример — парсинг исходного значения:
Можно ли просто использовать [JsonIgnore]?
Нет, в этом и проблема. System.Text.Json.Serialization.JsonIgnoreAttribute не влияет на связыватель конфигурации.
Замечание: начиная с .NET 9, связыватель уже пропускает свойства только для чтения (только-get/только-init при отсутствии соответствующего раздела). Предлагаемый здесь атрибут предназначен для свойств, доступных для записи, которые могут быть связаны, но не должны быть связаны.
См. также обсуждение проблемы на GitHub.
Источник: https://steven-giesel.com/blogPost/18a61100-6074-43ac-86ae-573ad66a2c8a/configurationignoreattribute-in-net-11
Атрибут ConfigurationIgnore в .NET 11
В Microsoft.Extensions.Configuration атрибут ConfigurationKeyNameAttribute существует с .NET 6 и позволяет переименовывать ключ, к которому привязано свойство. Но официального способа указать «не привязывать это свойство вообще» никогда не было. Этот пробел наконец-то устранён в .NET 11 с помощью ConfigurationIgnoreAttribute.
Проблема
Допустим, у вас есть класс параметров, который выглядит примерно так:
public class CsvIngestionOptions
{
// Вычисляется после загрузки – НЕ должен идти из конфигурации
public CsvFormatOptions DefaultFormat { get; set; }
// Раздел конфигурации, который мы привязываем и обрабатываем
public IConfigurationSection? DefaultFormatSection { get; set; }
// Вызывается после загрузки конфигурации, чтобы применить постобработку и значения по умолчанию
internal void OnConfigurationLoaded()
{
DefaultFormat = new CsvFormatOptions();
DefaultFormatSection?.Bind(DefaultFormat);
DefaultFormat.EnsureEncodingDefined();
}
}
DefaultFormat извлекается из DefaultFormatSection после некоторой постобработки. Его никогда не следует заполнять напрямую связывателем. Но поскольку у него есть публичные геттер и сеттер, система конфигурации пытается его связать.
Единственным обходным путём до .NET 11 было злоупотребление ConfigurationKeyNameAttribute с намеренно некорректным ключом:
// Костыль
[ConfigurationKeyName("__ignored_" + nameof(DefaultFormat))]
public CsvFormatOptions DefaultFormat { get; set; }
Это ненадёжно, вводит в заблуждение и создаёт странный код в вашей схеме конфигурации.
Решение
.NET 11 добавляет специальный атрибут ConfigurationIgnoreAttribute в Microsoft.Extensions.Configuration. Просто добавляем атрибут к тому свойству, которое не должно быть привязано:
public class CsvIngestionOptions
{
[ConfigurationIgnore]
public CsvFormatOptions DefaultFormat { get; set; }
[ConfigurationKeyName(nameof(DefaultFormat))]
public IConfigurationSection? DefaultFormatSection { get; set; }
// …
}
Ещё один распространённый сценарий
Постобработка — наиболее очевидный, но не единственный вариант использования. Ещё один классический пример — парсинг исходного значения:
public class FeatureFlags
{
public string RawFlags { get; set; } = string.Empty;
[ConfigurationIgnore]
public IReadOnlyDictionary<string, bool>
ParsedFlags { get; set; }
= new Dictionary<string, bool>();
}
Можно ли просто использовать [JsonIgnore]?
Нет, в этом и проблема. System.Text.Json.Serialization.JsonIgnoreAttribute не влияет на связыватель конфигурации.
Замечание: начиная с .NET 9, связыватель уже пропускает свойства только для чтения (только-get/только-init при отсутствии соответствующего раздела). Предлагаемый здесь атрибут предназначен для свойств, доступных для записи, которые могут быть связаны, но не должны быть связаны.
См. также обсуждение проблемы на GitHub.
Источник: https://steven-giesel.com/blogPost/18a61100-6074-43ac-86ae-573ad66a2c8a/configurationignoreattribute-in-net-11
День 2656. #SystemDesign101
Data Warehouse, Data Lake или Data Mesh
Хранение данных — это просто. Настоящая проблема — решить, где и как их организовать.
Хранилище данных (Data Warehouse) — это традиционный подход. Очищает и структурирует данные перед их сохранением. Запросы выполняются быстро, а отчёты остаются согласованными. Но добавление нового источника данных требует усилий, поскольку всё должно сначала соответствовать схеме.
Озеро данных (Data Lake) использует противоположный подход. Хранит все данные в необработанном виде, например, базы данных, журналы, изображения и видео. Обрабатывает их по мере необходимости. Гибкость — это здорово, но, если правила именования, форматирования и владения данными не установлены должным образом, вы получите дублирующиеся, устаревшие и недокументированные данные, которыми трудно управлять.
Сетка данных (Data Mesh) переносит владение данными от центральной команды к отдельным подразделениям. Например, отдел продаж публикует данные о продажах, а финансовый отдел — финансовые данные. Общие стандарты обеспечивают совместимость между командами.
Это хорошо работает в крупных организациях. Но для этого каждой команде необходимы подходящие люди и процессы для управления качеством данных, документацией и доступом к ним, что является непростой задачей.
На практике многие компании используют несколько подходов. Они используют хранилище данных для панелей мониторинга и отчетности, озеро данных для рабочих нагрузок машинного обучения и начинают применять принципы сетевой архитектуры по мере роста команд.
Источник: https://bytebytego.com/
Data Warehouse, Data Lake или Data Mesh
Хранение данных — это просто. Настоящая проблема — решить, где и как их организовать.
Хранилище данных (Data Warehouse) — это традиционный подход. Очищает и структурирует данные перед их сохранением. Запросы выполняются быстро, а отчёты остаются согласованными. Но добавление нового источника данных требует усилий, поскольку всё должно сначала соответствовать схеме.
Озеро данных (Data Lake) использует противоположный подход. Хранит все данные в необработанном виде, например, базы данных, журналы, изображения и видео. Обрабатывает их по мере необходимости. Гибкость — это здорово, но, если правила именования, форматирования и владения данными не установлены должным образом, вы получите дублирующиеся, устаревшие и недокументированные данные, которыми трудно управлять.
Сетка данных (Data Mesh) переносит владение данными от центральной команды к отдельным подразделениям. Например, отдел продаж публикует данные о продажах, а финансовый отдел — финансовые данные. Общие стандарты обеспечивают совместимость между командами.
Это хорошо работает в крупных организациях. Но для этого каждой команде необходимы подходящие люди и процессы для управления качеством данных, документацией и доступом к ним, что является непростой задачей.
На практике многие компании используют несколько подходов. Они используют хранилище данных для панелей мониторинга и отчетности, озеро данных для рабочих нагрузок машинного обучения и начинают применять принципы сетевой архитектуры по мере роста команд.
Источник: https://bytebytego.com/
👎1
День 2657. #ВопросыНаСобеседовании
Марк Прайс предложил свой набор из 60 вопросов (как технических, так и на софт-скилы), которые могут задать на собеседовании.
33. Разработка веб-API
«Расскажите, как бы вы спроектировали и реализовали веб-API, используя возможности минимальных API? Опишите шаги, необходимые для создания минимального API, и как это упрощает разработку API по сравнению с более ранними версиями Web API».
Хороший ответ
Минимальные API обеспечивают упрощённый подход к созданию высокопроизводительных, легковесных HTTP API. Вот как я бы спроектировал и реализовал минимальный API.
1. Создать новый проект Web API можно с помощью команды:
2. В Program.cs создадим нужные конечные точки. Минимальные API используют лямбда-выражения для обработки запросов непосредственно в коде, что упрощает маршрутизацию и настройку контроллера:
3. Настроим необходимые сервисы, такие как контекст БД, в настройках конструктора:
4. Тестировать API можно с помощью Postman или Swagger. .NET поддерживает Swagger по умолчанию:
Преимущества минимальных API
- Уменьшение шаблонного кода: устраняет необходимость в отдельных контроллерах, делая кодовую базу проще и меньше.
- Простота использования: упрощает настройку маршрутизации, облегчая создание и управление API.
- Производительность: предлагает легковесную альтернативу традиционным MVC-архитектурам, потенциально повышая производительность. Проекты минимальных API могут быть скомпилированы с использованием нативного AOT для ещё большей производительности.
Этот подход использует новейшие возможности .NET для эффективного создания API, фокусируясь на простоте и производительности.
Часто встречающийся плохой ответ
«Минимальные API подходят только для тестов и самых простых проектов и не предлагают ничего такого, чего не могли бы сделать контроллеры. Лучше придерживаться стандартного шаблона MVC».
Почему это неверно
- Сопротивление новым функциям: этот ответ демонстрирует сопротивление внедрению новых фреймворков и улучшений в технологиях. Минимальные API были введены для упрощения и ускорения разработки простых API, и они специально разработаны для улучшения опыта разработчиков и производительности в подходящих сценариях.
- Непонимание сценария использования: в ответе не учитывается, что минимальные API идеально подходят для приложений, которые не требуют полной структуры MVC, особенно для микросервисов или простых CRUD-операций.
- Отсутствие гибкости: ответ указывает на отсутствие гибкости в применении новых методов, которые могут обеспечить повышение эффективности в конкретных сценариях использования.
Этот ответ часто проистекает из недостаточного понимания конкретных преимуществ новых функций или из комфорта с устоявшимися шаблонами, которые не всегда могут быть наиболее эффективным выбором в каждом сценарии.
Источник: https://github.com/markjprice/tools-skills-net8/blob/main/docs/interview-qa/readme.md
Марк Прайс предложил свой набор из 60 вопросов (как технических, так и на софт-скилы), которые могут задать на собеседовании.
33. Разработка веб-API
«Расскажите, как бы вы спроектировали и реализовали веб-API, используя возможности минимальных API? Опишите шаги, необходимые для создания минимального API, и как это упрощает разработку API по сравнению с более ранними версиями Web API».
Хороший ответ
Минимальные API обеспечивают упрощённый подход к созданию высокопроизводительных, легковесных HTTP API. Вот как я бы спроектировал и реализовал минимальный API.
1. Создать новый проект Web API можно с помощью команды:
dotnet new webapi2. В Program.cs создадим нужные конечные точки. Минимальные API используют лямбда-выражения для обработки запросов непосредственно в коде, что упрощает маршрутизацию и настройку контроллера:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/products", async (AppDbContext db) =>
await db.Products.ToListAsync());
app.MapGet("/products/{id}",
async (int id, AppDbContext db) =>
await db.Products.FindAsync(id) is Product product ?
Results.Ok(product) : Results.NotFound());
app.MapPost("/products",
async (Product product, AppDbContext db) =>
{
db.Products.Add(product);
await db.SaveChangesAsync();
return Results.Created($"/products/{product.Id}", product);
});
//…
app.MapDelete("/products/{id}",
async (int id, AppDbContext db) =>
{
if (await db.Products.FindAsync(id) is Product product)
{
db.Products.Remove(product);
await db.SaveChangesAsync();
return Results.Ok(product);
}
return Results.NotFound();
});
app.Run();
3. Настроим необходимые сервисы, такие как контекст БД, в настройках конструктора:
builder.Services.AddDbContext<AppDbContext>(opts =>
opts.UseSqlServer(builder.Configuration
.GetConnectionString("DefaultConnection")));
4. Тестировать API можно с помощью Postman или Swagger. .NET поддерживает Swagger по умолчанию:
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
Преимущества минимальных API
- Уменьшение шаблонного кода: устраняет необходимость в отдельных контроллерах, делая кодовую базу проще и меньше.
- Простота использования: упрощает настройку маршрутизации, облегчая создание и управление API.
- Производительность: предлагает легковесную альтернативу традиционным MVC-архитектурам, потенциально повышая производительность. Проекты минимальных API могут быть скомпилированы с использованием нативного AOT для ещё большей производительности.
Этот подход использует новейшие возможности .NET для эффективного создания API, фокусируясь на простоте и производительности.
Часто встречающийся плохой ответ
«Минимальные API подходят только для тестов и самых простых проектов и не предлагают ничего такого, чего не могли бы сделать контроллеры. Лучше придерживаться стандартного шаблона MVC».
Почему это неверно
- Сопротивление новым функциям: этот ответ демонстрирует сопротивление внедрению новых фреймворков и улучшений в технологиях. Минимальные API были введены для упрощения и ускорения разработки простых API, и они специально разработаны для улучшения опыта разработчиков и производительности в подходящих сценариях.
- Непонимание сценария использования: в ответе не учитывается, что минимальные API идеально подходят для приложений, которые не требуют полной структуры MVC, особенно для микросервисов или простых CRUD-операций.
- Отсутствие гибкости: ответ указывает на отсутствие гибкости в применении новых методов, которые могут обеспечить повышение эффективности в конкретных сценариях использования.
Этот ответ часто проистекает из недостаточного понимания конкретных преимуществ новых функций или из комфорта с устоявшимися шаблонами, которые не всегда могут быть наиболее эффективным выбором в каждом сценарии.
Источник: https://github.com/markjprice/tools-skills-net8/blob/main/docs/interview-qa/readme.md
👎11👍2
День 2658. #Карьера
Дорожная Карта .NET Разработчика в 2026. Начало
Чтобы стать успешным .NET разработчиком, не нужно запоминать фреймворки или гнаться за каждым новым релизом. Необходимо сформировать прочные базовые знания, выбрать правильную специализацию и постепенно развиваться до уровня, позволяющего проектировать, создавать и поддерживать готовые к производству системы. Эта дорожная карта призвана помочь вам уверенно продвигаться вперёд, независимо от того, начинаете ли вы свой путь или уже работаете в экосистеме .NET.
I. Основы (обязательно)
Перед специализацией каждый .NET-разработчик должен освоить общий набор фундаментальных принципов. Их пропуск приводит к хрупкости знаний и медленному карьерному росту.
1. Основы разработки
- Как работает веб (запросы, ответы, методы HTTP);
- Базовые концепции работы с сетью;
- Принципы чистого кода и ООП;
- Системы контроля версий Git (ветвления, коммиты, пул-реквесты).
Эти навыки применимы везде, а не только в .NET.
2. Основы .NET и C#
- Современный синтаксис и особенности языка C#;
- Концепции среды выполнения .NET;
- Использование CLI для сборки и запуска проектов;
- Уверенная работа в IDE (Visual Studio, VS Code, Rider).
Не спешите с этим шагом. Прочные основы здесь окупятся на долгие годы.
3. Создание первого бэкенда
- Создание простого веб-API;
- Понимание маршрутизации, контроллеров и внедрения зависимостей;
- Подключение к реляционной БД;
- Выполнение базовых CRUD-операций;
- Использование ORM и понимание, что происходит «под капотом».
Цель — не совершенство, а уверенность.
4. ИИ как помощник в программировании
Инструменты ИИ могут ускорить повторяющиеся задачи, предложить решения и помочь быстро исследовать новые паттерны. Разбирайте генерируемый код, проверяйте его и интегрируйте продуманно. Думайте об ИИ как о помощнике, который повышает производительность, а не о чём-то, что пишет код за вас. Чем прочнее ваши базовые знания, тем эффективнее вы сможете использовать ИИ, не теряя контроля. Используйте ИИ для:
- Изучения идей;
- Повышения продуктивности;
- Быстрого выявления закономерностей.
II. Выбор направления
Настало время специализации. Не нужно изучать всё, нужно изучать то, что соответствует вашим целям.
1. Путь бэкенд-разработчика
Работа с API, данными, производительностью и масштабируемостью.
Ключевые навыки:
- Проектирование API и лучшие практики;
- Аутентификация и авторизация;
- Обработка ошибок и логирование;
- Валидация и чистая архитектура;
- Кэширование и оптимизация производительности;
- Фоновая обработка;
- Модульное и интеграционное тестирование.
Бэкенд-разработчики отвечают за надёжность и корректность — здесь глубина знаний важнее широты.
2. Путь Blazor-разработчика
Создание интерактивных веб-приложений на C#.
Ключевые навыки:
- Разработка компонентного UI;
- Маршрутизация и проектирование компоновки;
- Обработка и валидация форм;
- Стратегии управления состоянием;
- Фреймворки и стилизация UI;
- Основы JavaScript-интеропа;
- Тестирование компонентов UI.
Этот путь хорошо подходит для корпоративных приложений, панелей мониторинга и внутренних инструментов.
3. Путь фулстек-разработчика
Объединение бэкенд API с фронтенд-приложениями.
Ключевые навыки:
- Проектирование API;
- Создание UI, использующего API;
- Обработка сквозной аутентификации;
- Управление общими моделями и контрактами;
- Понимание как производительности, так и пользовательского опыта.
Этот путь требует баланса — не поверхностных знаний, а универсальности.
Окончание следует…
Источник: https://www.c-sharpcorner.com/article/a-practical-net-developer-roadmap-for-2026/
Дорожная Карта .NET Разработчика в 2026. Начало
Чтобы стать успешным .NET разработчиком, не нужно запоминать фреймворки или гнаться за каждым новым релизом. Необходимо сформировать прочные базовые знания, выбрать правильную специализацию и постепенно развиваться до уровня, позволяющего проектировать, создавать и поддерживать готовые к производству системы. Эта дорожная карта призвана помочь вам уверенно продвигаться вперёд, независимо от того, начинаете ли вы свой путь или уже работаете в экосистеме .NET.
I. Основы (обязательно)
Перед специализацией каждый .NET-разработчик должен освоить общий набор фундаментальных принципов. Их пропуск приводит к хрупкости знаний и медленному карьерному росту.
1. Основы разработки
- Как работает веб (запросы, ответы, методы HTTP);
- Базовые концепции работы с сетью;
- Принципы чистого кода и ООП;
- Системы контроля версий Git (ветвления, коммиты, пул-реквесты).
Эти навыки применимы везде, а не только в .NET.
2. Основы .NET и C#
- Современный синтаксис и особенности языка C#;
- Концепции среды выполнения .NET;
- Использование CLI для сборки и запуска проектов;
- Уверенная работа в IDE (Visual Studio, VS Code, Rider).
Не спешите с этим шагом. Прочные основы здесь окупятся на долгие годы.
3. Создание первого бэкенда
- Создание простого веб-API;
- Понимание маршрутизации, контроллеров и внедрения зависимостей;
- Подключение к реляционной БД;
- Выполнение базовых CRUD-операций;
- Использование ORM и понимание, что происходит «под капотом».
Цель — не совершенство, а уверенность.
4. ИИ как помощник в программировании
Инструменты ИИ могут ускорить повторяющиеся задачи, предложить решения и помочь быстро исследовать новые паттерны. Разбирайте генерируемый код, проверяйте его и интегрируйте продуманно. Думайте об ИИ как о помощнике, который повышает производительность, а не о чём-то, что пишет код за вас. Чем прочнее ваши базовые знания, тем эффективнее вы сможете использовать ИИ, не теряя контроля. Используйте ИИ для:
- Изучения идей;
- Повышения продуктивности;
- Быстрого выявления закономерностей.
II. Выбор направления
Настало время специализации. Не нужно изучать всё, нужно изучать то, что соответствует вашим целям.
1. Путь бэкенд-разработчика
Работа с API, данными, производительностью и масштабируемостью.
Ключевые навыки:
- Проектирование API и лучшие практики;
- Аутентификация и авторизация;
- Обработка ошибок и логирование;
- Валидация и чистая архитектура;
- Кэширование и оптимизация производительности;
- Фоновая обработка;
- Модульное и интеграционное тестирование.
Бэкенд-разработчики отвечают за надёжность и корректность — здесь глубина знаний важнее широты.
2. Путь Blazor-разработчика
Создание интерактивных веб-приложений на C#.
Ключевые навыки:
- Разработка компонентного UI;
- Маршрутизация и проектирование компоновки;
- Обработка и валидация форм;
- Стратегии управления состоянием;
- Фреймворки и стилизация UI;
- Основы JavaScript-интеропа;
- Тестирование компонентов UI.
Этот путь хорошо подходит для корпоративных приложений, панелей мониторинга и внутренних инструментов.
3. Путь фулстек-разработчика
Объединение бэкенд API с фронтенд-приложениями.
Ключевые навыки:
- Проектирование API;
- Создание UI, использующего API;
- Обработка сквозной аутентификации;
- Управление общими моделями и контрактами;
- Понимание как производительности, так и пользовательского опыта.
Этот путь требует баланса — не поверхностных знаний, а универсальности.
Окончание следует…
Источник: https://www.c-sharpcorner.com/article/a-practical-net-developer-roadmap-for-2026/
👍8👎2
День 2659. #Карьера
Дорожная Карта .NET Разработчика в 2026. Окончание
Начало
III. Продвинутые навыки
Сеньоров определяет не количество изученных фреймворков, а образ мышления.
1. Проектирование и архитектура систем
- Структура и модульность приложений;
- Компромиссы между монолитами и распределёнными системами;
- Шаблоны масштабируемости и отказоустойчивости;
- Мониторинг и диагностика.
2. Контейнеры и доставка
Современное ПО не ограничивается принципом «работает на моей машине»:
- Концепции контейнеризации;
- Локальные и производственные среды;
- Автоматизированные сборки и развёртывания;
- Понимание конвейеров выпуска.
3. Облачные технологии
- Как размещаются приложения в облаке;
- Конфигурация среды;
- Основы безопасности;
- Вопросы стоимости и производительности.
4. Инструменты, упрощающие жизнь
Библиотеки и инструменты для:
- Логирования;
- Валидации;
- Маппинга;
- Тестирования;
- Фоновых задач;
- UI-компонентов.
Инструменты меняются. Концепции остаются. Сосредоточьтесь на том, почему они вам нужны, а не только на том, как их использовать.
IV. Часто игнорируемый навык: Коммуникация
Отличные разработчики:
- Пишут чёткие сообщения коммитов;
- Просто объясняют технические решения;
- Документируют системы для будущих коллег;
- Задают правильные вопросы.
Эти навыки часто важнее, чем знание ещё одного фреймворка.
Последовательность обучения
1. Git и основы программирования
2. Основы C#
3. Основы ASP.NET Core
4. Базы данных и доступ к данным
5. Выбор специализации
6. Создание реальных проектов
7. Развёртывание и архитектура
Итого
В разработке ПО нет финишной линии. Цель не в том, чтобы «знать всё», а в том, чтобы стать человеком, способным постоянно учиться и решать важные проблемы. Будьте последовательны. Создавайте. Размышляйте.
Источник: https://www.c-sharpcorner.com/article/a-practical-net-developer-roadmap-for-2026/
Дорожная Карта .NET Разработчика в 2026. Окончание
Начало
III. Продвинутые навыки
Сеньоров определяет не количество изученных фреймворков, а образ мышления.
1. Проектирование и архитектура систем
- Структура и модульность приложений;
- Компромиссы между монолитами и распределёнными системами;
- Шаблоны масштабируемости и отказоустойчивости;
- Мониторинг и диагностика.
2. Контейнеры и доставка
Современное ПО не ограничивается принципом «работает на моей машине»:
- Концепции контейнеризации;
- Локальные и производственные среды;
- Автоматизированные сборки и развёртывания;
- Понимание конвейеров выпуска.
3. Облачные технологии
- Как размещаются приложения в облаке;
- Конфигурация среды;
- Основы безопасности;
- Вопросы стоимости и производительности.
4. Инструменты, упрощающие жизнь
Библиотеки и инструменты для:
- Логирования;
- Валидации;
- Маппинга;
- Тестирования;
- Фоновых задач;
- UI-компонентов.
Инструменты меняются. Концепции остаются. Сосредоточьтесь на том, почему они вам нужны, а не только на том, как их использовать.
IV. Часто игнорируемый навык: Коммуникация
Отличные разработчики:
- Пишут чёткие сообщения коммитов;
- Просто объясняют технические решения;
- Документируют системы для будущих коллег;
- Задают правильные вопросы.
Эти навыки часто важнее, чем знание ещё одного фреймворка.
Последовательность обучения
1. Git и основы программирования
2. Основы C#
3. Основы ASP.NET Core
4. Базы данных и доступ к данным
5. Выбор специализации
6. Создание реальных проектов
7. Развёртывание и архитектура
Итого
В разработке ПО нет финишной линии. Цель не в том, чтобы «знать всё», а в том, чтобы стать человеком, способным постоянно учиться и решать важные проблемы. Будьте последовательны. Создавайте. Размышляйте.
Источник: https://www.c-sharpcorner.com/article/a-practical-net-developer-roadmap-for-2026/
👍11👎2
День 2660. #ЗаметкиНаПолях
Отключаем HTTP-Кэширование по Умолчанию в ASP.NET Core API
При создании API в ASP.NET Core крайне важно явно контролировать поведение кэширования. В отличие от веб-страниц, где кэширование часто улучшает пользовательский опыт, ответы API не следует кэшировать по умолчанию, если вы намеренно не предусмотрели возможность их кэширования. Непреднамеренное кэширование может привести к серьёзным проблемам, включая устаревшие данные, уязвимости безопасности и трудновоспроизводимые ошибки.
Стандарты кэширования в HTTP
Кэширование HTTP регулируется RFC 7234 (Кэширование в HTTP/1.1) и RFC 9111 (HTTP Кэширование). В соответствии с этими спецификациями, кэши разных уровней могут хранить ответы и предоставлять их без обращения к исходному серверу, используя заголовки, такие как
При отсутствии заголовков кэши могут применять эвристическое истечение срока действия, кэшируя ответы API даже без явных на то указаний. Это особенно проблематично, поскольку браузеры и промежуточные кэши (такие как CDN, прокси или кэши шлюзов) могут использовать собственные алгоритмы для определения того, как долго хранить ответ.
Реализация промежуточного ПО с запретом кэширования
Чтобы гарантировать, что ответы API не будут кэшироваться по умолчанию, реализуйте промежуточное ПО, которое устанавливает соответствующие заголовки управления кэшированием. Оно добавляет необходимые заголовки, чтобы предотвратить кэширование, если вы явно не переопределите их в конкретных контроллерах или действиях.
Вот как создать такое промежуточное ПО:
Регистрируем наше промежуточное ПО в конвейере:
Источник: https://www.meziantou.net/disable-http-caching-by-default-in-asp-net-core-apis.htm
Отключаем HTTP-Кэширование по Умолчанию в ASP.NET Core API
При создании API в ASP.NET Core крайне важно явно контролировать поведение кэширования. В отличие от веб-страниц, где кэширование часто улучшает пользовательский опыт, ответы API не следует кэшировать по умолчанию, если вы намеренно не предусмотрели возможность их кэширования. Непреднамеренное кэширование может привести к серьёзным проблемам, включая устаревшие данные, уязвимости безопасности и трудновоспроизводимые ошибки.
Стандарты кэширования в HTTP
Кэширование HTTP регулируется RFC 7234 (Кэширование в HTTP/1.1) и RFC 9111 (HTTP Кэширование). В соответствии с этими спецификациями, кэши разных уровней могут хранить ответы и предоставлять их без обращения к исходному серверу, используя заголовки, такие как
Cache-Control, Expires, ETag и Last-Modified.При отсутствии заголовков кэши могут применять эвристическое истечение срока действия, кэшируя ответы API даже без явных на то указаний. Это особенно проблематично, поскольку браузеры и промежуточные кэши (такие как CDN, прокси или кэши шлюзов) могут использовать собственные алгоритмы для определения того, как долго хранить ответ.
Реализация промежуточного ПО с запретом кэширования
Чтобы гарантировать, что ответы API не будут кэшироваться по умолчанию, реализуйте промежуточное ПО, которое устанавливает соответствующие заголовки управления кэшированием. Оно добавляет необходимые заголовки, чтобы предотвратить кэширование, если вы явно не переопределите их в конкретных контроллерах или действиях.
Вот как создать такое промежуточное ПО:
internal sealed class
NoCacheMiddleware(RequestDelegate next)
{
public async Task InvokeAsync(HttpContext ctx)
{
ctx.Response.OnStarting(() =>
{
// Устанавливаем заголовки no-cache, только если не были установлены явно
if (ctx.Response.Headers.CacheControl.Count is 0)
ctx.Response.Headers.CacheControl =
"no-cache,no-store,must-revalidate";
return Task.CompletedTask;
});
await next(ctx);
}
}
Регистрируем наше промежуточное ПО в конвейере:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseMiddleware<NoCacheMiddleware>();
app.MapGet("/", () => "Hello World!");
app.Run();
Источник: https://www.meziantou.net/disable-http-caching-by-default-in-asp-net-core-apis.htm
👍11👎1