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

Для связи: @SBenzenko

Поддержать канал:
- https://boosty.to/netdeveloperdiary
- https://patreon.com/user?u=52551826
- https://pay.cloudtips.ru/p/70df3b3b
Download Telegram
День 2044. #Testing
Автоматизированные Тесты. Продолжение

Начало

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

Пишите код помогающий писать тесты
Написание теста должно быть простым, а тестовый код — понятным. Важно создать тестовую инфраструктуру, которая упрощает процесс написания тестов. Часто используют класс TestContext, содержащий общий код для написания тестов. Например, он может содержать код запуска приложения, отправки запроса, подтверждения ответа, регистрации мока и т. д. Так вы сможете сосредоточиться на написании теста, а не на шаблонном коде:
// Arrange
using var ctx = new TestContext();
ctx.ReplaceService<IService, MockImplementation>();
ctx.SetConfigurationFile("""{ "path: "/tmp" }""");
ctx.SeedDatabase(db =>
db.Users.Add(new User { Username = "user" }));
var user = ctx.SetCurrentUser("user");

// Act
var response = await ctx.Get("/user");

// Assert
Assert.AreEqual(response, """
Id: 1
UserName: user
""");


Нужно ли имитировать зависимости?
Моки (Moq) — способ протестировать приложение без использования реальных зависимостей. Поэтому, используя моки, вы тестируете не реальное приложение, а его разновидность. Важно максимально приблизить эту разновидность к реальности. Может быть сложно поддерживать тесты с моками. Сервисы, которые вы имитируете, могут изменить поведение, и вы можете не заметить этого, поскольку не используете их напрямую. Также приходится писать много кода для настройки тестов.

Разработчики, как правило, используют слишком много моков. Нужно ли имитировать файловую систему? Это не так-то просто, и у многих неправильные предположения о ней. Например, в Windows она чувствительна к регистру, некоторые имена файлов или символы в них недопустимы. В случае кроссплатформенного приложения может потребоваться протестировать поведение, специфичное для ОС. Почему бы просто не писать во временный каталог? То же самое касается БД. Можно использовать Docker для запуска БД, чтобы протестировать SQL и ограничения базы?

В большинстве случаев нужно имитировать внешние сервисы, которые не находятся под вашим контролем. Рассмотрите возможность использования фактических сервисов, когда это возможно. Конечно, желательно, чтобы тесты были изолированы. Здесь есть много стратегий. Например, если нужно читать или записывать файлы, можно создать временный каталог для каждого теста. Если вы запускаете БД в контейнере, можно использовать разные имена баз для изоляции тестов. Можно положиться на эмуляторы, предоставляемые поставщиками облачных услуг, для локального запуска некоторых зависимостей. Так вы будете уверены, что код работает, как ожидалось, и не нужно писать сложные моки. Убедитесь, что приложение можно настроить, например, легко подставлять разные строки соединений или папки для хранения данных приложения.

Полезные инструменты для избежания моков
- TestContainers или .NET Aspire. Если запуск Docker-контейнера медленный, можно переиспользовать его между несколькими тестовыми запусками. .NET Aspire также может предоставлять ресурсы в облаке (Azure, AWS и т. д.).
- Эмуляторы облачных сервисов. Например, Azure предоставляет эмулятор для хранилища.

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

Источник:
https://www.meziantou.net/automated-tests.htm
👍15👎1
День 2045. #Testing
Автоматизированные Тесты. Продолжение

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

Фреймворки-имитаторы
Фреймворки-имитаторы могут быть полезны для тестирования сценариев, которые трудно воспроизвести. Например, проверить, может ли приложение обрабатывать определённую ошибку, возвращаемую сторонним API. Тогда можно имитировать API, чтобы вернуть ожидаемую ошибку.

Я стараюсь избегать использования фреймворков-имитаторов, а создавать тестовые двойники вручную. Тестовые двойники могут более точно имитировать реальные сценарии, чем фреймворки-имитаторы. Они могут сохранять состояние между несколькими вызовами методов, что может быть сложно с фреймворками-имитаторами. Может потребоваться убедиться, что мок вызывается в правильном порядке (например, Save перед Get – хотя это можно сделать), или что вызывается правильное количество раз.

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

Это может показаться более трудоёмким, но эти усилия не существенны. Обычно вы не имеете дело с чрезмерным количеством фиктивных классов, и можете повторно использовать обобщённую реализацию в различных тестах. Так вы избегаете дублирования блоков кода для настройки в каждом тесте.
// Используем фреймворк-имитатор FakeItEasy
// Что, если сервис вызовет GetAsync до SaveAsync?
var service = A.Fake<IService>();
A.CallTo(() => service.SaveAsync()).Returns(true);
A.CallTo(() => service.GetAsync()).Returns(["value"]);

var sut = new MyClass(service);
sut.DoSomething();

Сравните с:
// Используем собственный двойник 
var service = new StubService();
service.AddItem("value"); // Добавляем данные

var sut = new MyClass(service);
sut.DoSomething();


Нужно ли добавлять интерфейсы, чтобы иметь возможность имитировать?
Интерфейсы с единственной реализацией бесполезны. Они просто добавляют сложности коду. По возможности не усложняйте код только для того, чтобы иметь возможность использовать моки. Если в коде будет единственная реализация, то вам может не понадобиться интерфейс. Кроме того, можно создать мок самого класса, а не интерфейса.

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

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

Источник:
https://www.meziantou.net/automated-tests.htm
Автор оригинала: Gérald Barré
👍7👎1
День 2046. #Testing
Автоматизированные Тесты. Окончание

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

Пишите больше утверждений в коде
Хотя утверждения (Assert) в тестах являются наиболее распространённым способом проверки поведения кода, можно писать утверждения и в коде. Например, использовать Debug.Assert для проверки состояния приложения. Это может быть полезно для проверки некоторых предположений, которые у вас есть относительно кода. Одним из преимуществ является то, что ошибка будет возникать на ранней стадии и также при отладке приложения, а не только при запуске тестов.

Утверждения также могут улучшить читаемость кода. Вы можете увидеть ожидаемое поведение непосредственно в коде, что может быть полезно при написании сложного кода или когда вы хотите проверить определённое поведение:
public void DoSomething()
{
Debug.Assert(_service != null,
"Этого быть не должно!");
_service.DoSomething();
}


Тестовые фреймворки
Используйте тот, который вам больше нравится: xUnit, NUnit и MSTests очень похожи по функциям. Синтаксис может отличаться, но концепции одинаковы. Для утверждений можно использовать встроенные или библиотеку вроде FluentAssertions.

Покрытие
Не стоит стремиться к 100% покрытию тестами. Вот некоторые проблемы с этой метрикой:
- 100% покрытие означает, что ошибок нет? Нет, это просто означает, что весь код покрыт тестами. И чаще всего только ваш код, но не зависимости.
- Сколько времени вы потратите на написание тестов, чтобы покрыть последние 10% кода? Стоит ли оно того?
- Нужно ли покрывать все пути в коде? Например, если есть метод, который выдаёт ArgumentNullException, нужно ли его тестировать? Добавляет ли это больше уверенности в коде или это просто пустая трата времени?

Вместо этого сосредоточьтесь на покрытии большей части кода. 70-80% часто является хорошим компромиссом с точки зрения уверенности и усилий. Это означает, что есть тесты, которые покрывают большую часть кода, и вы не тратите слишком много времени на их написание. Не забывайте, что тесты предназначены для того, чтобы придать достаточно уверенности в коде. Не нужно тестировать всё.

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

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

Есть несколько способов справиться с нестабильными тестами:
- Исправить тест - лучшее решение.
- Поместить тест в карантин и создать задачу для его исправления позже.
- Удалить тест, если он бесполезен.

Некоторые инструменты CI могут обнаружить нестабильность теста. Например, Azure DevOps может это делать.

См. также:
-
Мутационное тестирование с помощью Stryker
-
Пишите Тесты Быстрее с Approval Tests

Источник: https://www.meziantou.net/automated-tests.htm
👍5
День 2047. #УрокиРазработки
Уроки 50 Лет Разработки ПО

Урок 22. Проблемы многих систем скрываются в интерфейсах. Начало

Простейшая программа состоит из единственного модуля кода и UI. Интерфейс описывает, как стыкуются два архитектурных элемента внутри многокомпонентной системы или система c внешним окружением. Некоторые интерфейсы должны соответствовать установленным стандартам и протоколам, другие характерны для конкретного приложения.

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

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

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

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

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

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

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

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

Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 3.
👍7
День 2048. #УрокиРазработки
Уроки 50 Лет Разработки ПО

Урок 22. Проблемы многих систем скрываются в интерфейсах. Окончание

Начало

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

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

Проверка входных данных
Каждый компонент, участвующий во взаимодействии, должен проверять получаемые входные данные перед их обработкой. Многие уязвимости безопасности обусловлены тем, что вредоносный код, внедряемый злоумышленником через интерфейс, не отклоняется как недопустимый ввод. Хорошо спроектированная система будет правильно обрабатывать исключения, возникающие во внутренних и внешних интерфейсах. Компьютер, который внезапно «теряет» сетевой принтер, и не может найти его без перезагрузки – это проблема интерфейса взаимодействия.

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

Хорошо спроектированные интерфейсы не должны требовать вспомогательной документации в виде справочных экранов и руководств. Они облегчают пользователям процесс освоения нового приложения и оберегают их от ошибок. Одна из книг, посвящённых UI, — классический труд Алана Купера «Интерфейс. Основы проектирования взаимодействия». Ориентируясь на сценарии использования, а не на функции продукта, вы сможете избежать многих проблем с пользовательским опытом.

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

Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 3.
👍8
День 2049. #юмор
👍17👎2
День 2050.
Извините за повтор, но есть хорошие новости.

DotNext 2024 стартует уже сегодня.
Я выступаю в 10:30 по Москве с докладом «Что нового в .NET 9». А посмотреть мой (и ещё несколько) докладов можно абсолютно бесплатно в рамках Community Day. Всё, что нужно – это зарегистрироваться.

В общем, я пошёл готовиться, буду рад видеть всех, кто приедет. А в онлайне смотрите, задавайте вопросы, ну и лайки там, отзывы по выступлению, вотэтовсё 😉

До встречи!
👍52
День 2051. #Testing
Введение в WebApplicationFactory. Начало

Сегодня рассмотрим, что такое WebApplicationFactory и как она помогает в тестировании.

Мотивация
Все мы знаем про юнит-тесты, интеграционные тесты и End-to-end тесты. Чёткого разграничения нет. Спросите 10 разработчиков, и они дадут вам 10 разных определений. Но несомненно, что есть код, если модули кода, и их как-то надо тестировать.

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

Преимущества
1. Если контракт поменяется (как в WebAPI), тест не пройдёт.
2. Вы тестируете всю цепочку и пишете тесты с точки зрения конечного пользователя (не полагаясь на технические детали).
3. Вы получаете хороший обзор ваших функций, таким образом создавая «живую документацию» своего кода.

WebApplicationFactory
Это упрощённый сервер в памяти, который запускает ваш WebAPI ASP.NET Core. Она применит все настройки приложения (включая application.json), DI и будет работать с реальной БД (если не настроено иначе).
Вот простейший минимальный API для примера:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapPost("/", (HelloRequest request) =>
$"Hello {request.Name}!");

app.Run();

И простая запись для запроса:
public record HelloRequest(string Name); 


Настроим тестовый проект (xUnit, nUnit, MSTest – какой хотите).
Добавим NuGet-пакет Microsoft.AspNetCore.Mvc.Testing и ссылку с тестового проекта на основной.

Теперь можно написать код настройки тестов. В xUnit используется конструктор:
public class MyApiTests :
IClassFixture<WebApplicationFactory<Program>>
{
public void MyApiTests(
WebApplicationFactory<Program> factory)
{
}
}

Здесь IClassFixture<WebApplicationFactory<Program>> используется, чтобы указать xUnit передать WebApplicationFactory<Program> в конструктор.

Замечания:
1. Называйте классы и методы тестов как модули и их функции, которые вы хотите протестировать. Это важно, если вы хотите иметь живую документацию внутри своего кода.
2. Этот код не скомпилируется. Причина в том, что класс Program является внутренним (internal). В минимальных API больше нет метода Main, компилятор создаёт его за вас. Но теперь там используется модификатор internal. Одним из возможных исправлений было бы добавление InternalsVisibleTo, но это влечёт за собой много исправлений. Тогда тестовые методы также должны быть внутренними. Но внутренние методы не могут быть выполнены тестовой средой. Есть более простой «хак»: с помощью partial класса сделать класс Program публичным. Добавьте в конец файла Program.cs:
public partial class Program
{
}

Не идеально для минимальных API, но просто.

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

Источник:
https://steven-giesel.com/blogPost/cd62475b-2c7d-4ce2-bd97-9670f91ebac8/introduction-to-webapplicationfactory
👍18
День 2052. #Testing
Введение в WebApplicationFactory. Окончание
Начало

Теперь добавим тест. Для простых сценариев можно использовать HttpClient.
public class MyApiTests :
IClassFixture<WebApplicationFactory<Program>>
{
private readonly HttpClient client;

public MyApiTests(
WebApplicationFactory<Program> factory)
{
client = factory.CreateClient();
}

[Fact]
public async Task
PassingNameShouldReturnWelcomeMessage()
{
var resp =
await client.PostAsJsonAsync("/", new
{
Name = "Jon Smith"
});

Assert.True(resp.IsSuccessStatusCode);
var content =
await resp.Content.ReadAsStringAsync();
Assert.Equal("Hello Jon Smith!", content);
}
}

Почему мы передали анонимный объект, а не HelloRequest (он ведь публичный)? Несколько причин:
1. Он публичный, но не чтобы использовать в тестах. Помните, мы являемся пользователем API. Пользователь не знает внутреннего представления наших доменных объектов.
2. Тесты не должны пострадать, если мы поменяем доменную модель.
3. Мы также тестируем сериализацию и десериализацию.
Поэтому анонимный объект идеален.

Конфигурация
Есть много настроек WebApplicationFactory, которые можно сделать в конструкторе. Рассмотрим основные:
public MyApiTests(
WebApplicationFactory<Program> factory)
{
this.factory = factory.WithWebHostBuilder(
builder =>
{
// Изменить настройки из application.json
builder.UseSetting(
"ConnectionString",
"file=:memory:");

// Если в appsettings.json объект:
// MyObject {
// MyProp: 123
// }
// Используем нотацию ":"
builder.UseSetting("MyObject:MyProp", 234);

// Изменить среду и загружать
// настройки из appsettings.tests.json
builder.UseEnvironment("tests");

// Перенастроить сервисы
builder.ConfigureServices(
services => …
);
});
}


Источник: https://steven-giesel.com/blogPost/cd62475b-2c7d-4ce2-bd97-9670f91ebac8/introduction-to-webapplicationfactory
👍16
День 2053. #TipsAndTricks
Объединения по Нескольким Столбцам в Entity Framework

Я столкнулся с очень раздражающей «проблемой» с объединениями LINQ (left join) в Entity Framework.

Исходный запрос
var query = dbContext.Entity.Where(...);

var result = from e in query
join j in dbContext.JoinEntity
on new { e.Id, e.OtherId }
equals new { j.WId, j.OtherId } into group
from g in group.DefaultIfEmpty()
select new { e, g };


Этот запрос приводит к неприятной ошибке компилятора:
The type arguments cannot be inferred from the query. Candidates are: …
(Типы аргументов не могут быть выведены из запроса. Кандидаты: …) далее очень длинный текст.

Решение
Проблема в том, что я использовал несколько столбцов для объединения, но ВСЕ они должны иметь одинаковое имя, иначе компилятор не сможет вывести типы аргументов. Поэтому простое решение — что-то вроде:
var result = from e in query
join j in dbContext.JoinEntity
on new { WId = e.Id, OId = e.OtherId }
equals new { WId = j.WId, OId = j.OtherId } into group
from g in group.DefaultIfEmpty()
select new { e, g };

То есть оба столбца должны иметь одинаковое имя в анонимных типах. И да, можно было просто написать чистый SQL, но это отдельный вопрос.

Источник: https://steven-giesel.com/blogPost/78753461-d80f-4f81-9b4d-6484066aa43e/linq-joins-on-multiple-columns-in-entity-framework
Автор оригинала: Steven Giesel
👍15
День 2054. #УрокиРазработки
Уроки 50 Лет Разработки ПО

Урок 23. При планировании работ нужно учитывать «силу трения». Начало

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


Есть ли ошибки в рассуждениях менеджера? 40/8=5. На первый взгляд логично. Но здесь не учтены многие факторы, сокращающие время, которое люди могут потратить на работу над проектом в течение каждого дня. Есть разница между количеством рабочих часов и временем, фактически потраченным на выполнение работы. Это лишь один из множества факторов, которые должны учитывать и руководители проектов, и отдельные члены команды при переводе объёмов или усилий в календарное время.

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

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

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

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

2. Выработайте привычку решать только одну задачу в течение дня, на протяжении которой не будете отвлекаться на звонки или сообщения.

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

4. Делайте регулярные перерывы для восстановления сил. Концентрация в состоянии потока велика, но всё имеет пределы. Вы должны время от времени выходить из этого состояния, чтобы «глотнуть воздуха». Помассируйте уставшую шею, руки и плечи. Чтобы уменьшить нагрузку на глаза, периодически отводите взгляд от экрана монитора и на несколько секунд фокусируйтесь на чем-то вдалеке. Короткие перерывы умственной деятельности помогают отдохнуть и с новыми силами погрузиться в продуктивное состояние потока.

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

Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 4.
👍13
День 2055. #УрокиРазработки
Уроки 50 Лет Разработки ПО

Урок 23. При планировании работ нужно учитывать «силу трения». Окончание

Начало

Эффективные часы
На работе время утекает в самых разных направлениях: встречи, видеочаты, ответы на e-mail, обзоры кода и т.п. Удалённая работа из дома сопряжена с риском отвлечения на другие занятия, более увлекательные, чем работа над проектом. Даже работая 40 часов в неделю, вы едва ли будете тратить все их до минуты на проект.

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

Другие источники «трений» в проекте
Также команды теряют время из-за других источников «трений», например, поддержку существующих систем. Никто не может предсказать, когда что-то сломается или потребуется внести какое-то изменение, поэтому члены команды тратят время на выполнение незапланированной работы.

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

Из-за неясных и изменчивых приоритетов требований к исследованиям, на обсуждение и корректировку могут уходить часы. Команде может понадобиться временно отложить некоторые незавершённые дела, если в расписании появится новая задача с более высоким приоритетом. Незапланированные доработки также требуют времени.

Последствия планирования
«Трения» в проекте сильно влияют на оценку, и об этом следует помнить. Поэтому важно переводить идеальную оценку объёма работ в календарное время, опираясь на коэффициент эффективности рабочего времени, а также на возможность влияния других источников «трений».

Руководители редко учитывают влияние времени, потерянного из-за чрезмерной многозадачности. Руководитель любит перераспределять рабочее время людей между задачами: 50% сюда и 50% туда, или 50, 25 и 25. Но, когда наступает время подвести итоги, он забывает о процентах и думает, что все в команде заняты полный рабочий день, а потом удивляется тому, как много времени тратится «впустую». Кроме того, работа в нескольких командах означает необходимость тратить больше времени на собрания и меньше — на программирование.

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

Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 4.
👍10
День 2056. #ЗаметкиНаПолях #Cancellation
Отмена. Часть 5: Регистрация
Регистрация — это способ для вашего кода выполнить метод обратного вызова (callback) немедленно при запросе отмены. Этот метод может выполнить некоторую операцию (часто вызов другого API) для отмены асинхронной операции.

Внимание: из-за множества способов вызова обычно рекомендуется, чтобы callback-методы не выдавали исключения.

Как регистрировать
Ваш код может зарегистрировать callback-метод с любым токеном отмены, вызвав его метод Register. Callback-метод вызывается, когда (если) токен отменяется. Метод Register возвращает регистрацию токена отмены (структуру IDisposable).

Практически все асинхронные API в .NET поддержку отмены через токен, поэтому код ниже в качестве примера использует устаревший WebClient, который не принимает токена отмены:
async Task DownloadAsync(CancellationToken ct)
{
using var wc = new WebClient();
using var ctr =
ct.Register(() => wc.CancelAsync());

await wc.DownloadStringTaskAsync(
new Uri("https://www.google.com"));
}

Внимание: callback-метод может не быть вызван!
Задачи всегда должны завершаться, но некоторые токены отмены никогда не будут отменены, поэтому они никогда не вызовут свои callback-методы.

Состояние гонки
Что произойдёт, если токен отмены будет отменён примерно в то же время, когда зарегистрирован обратный вызов?
Если callback-метод добавляется к токену отмены, который уже отменён, то он немедленно и синхронно вызывается.

Важность очистки
При написании отменяемого кода убедитесь, что ваш код удаляет регистрацию; это предотвратит утечки ресурсов в приложении. using var registration в коде выше является одним из распространённых способов обработки очистки.

Внимание: синхронные вызовы callback-методов
Как обсуждалось в запросе отмены, источники токенов могут быть отменены путём вызова метода Cancel. Важно отметить, что любые зарегистрированные обратные вызовы немедленно (и синхронно) запускаются методом Cancel до того, как он вернёт управление. Это может стать источником взаимоблокировок или другого неожиданного поведения. Это неудобно, поэтому в .NET 8.0 был добавлен метод токена CancelAsync, который вызывает обратные вызовы отмены в потоке из пула.

Внимание: возможно, что CancelAsync вернётся до завершения обратных вызовов, если он уже был вызван.
Как только CancellationTokenSource перейдёт в отменённое состояние, любые последующие вызовы Cancel или CancelAsync вернутся немедленно, даже если предыдущий вызов CancelAsync ещё не завершил выполнение своих обратных вызовов.

Итого
Регистрация обратных вызовов — естественный способ реализации отмены на самых низких уровнях. Однако помните, что метод обратного вызова:
1. Не должен выдавать исключений.
2. Может никогда не быть вызван.
3. Может быть вызван немедленно в том же потоке до возврата из Register.
4. В большинстве случаев вызывается синхронно.
5. Регистрация обязательно должна удаляться.

Источник:
https://blog.stephencleary.com/2024/08/cancellation-5-registration.html
👍15
День 2057. #Карьера
Категории Руководства в Технических Командах. Начало

В технических проектах важно правильно структурировать, укомплектовывать команды и правильно руководить ими. Один из вариантов — разбить руководителей команд по категориям ответственности. Руководство охватывает огромный спектр вещей, и попытка найти кого-то, кто может быть хорош во всех, часто превращается в охоту за единорогом. Обычно люди хороши в 1-2 областях, и им лучше полностью сосредоточиться на них. Следующие категории являются хорошей отправной точкой для разделения ответственности по руководству командой, но, конечно, реальность всегда сложнее.

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

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

Важнейшим навыком является прогнозирование (как в масштабе команды, так и в масштабе компании), т.к. расстановка приоритетов сводится к вопросу: «Какой эффект будет от реализации нашей командой этого проекта?» Также важно уметь хорошо доносить эти прогнозы, приоритеты и цели команды до других заинтересованных сторон.

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

2. Управление людьми
Означает ответственность за успех людей в команде, чаще всего включающую:
- Коучинг людей для роста их навыков и карьеры.
- Разработку и контроль процессов найма для команды.
- Установление и сообщение ожиданий производительности и их оценка.

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

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

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

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

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

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

Источник:
https://www.benkuhn.net/leadcats/
👍5
День 2058. #Карьера
Категории Руководства в Технических Командах. Продолжение

Начало

3. Управление проектами
Означает обеспечение хорошей работы команды: то есть, чтобы каждый работал эффективно над приоритетами команды, не ждал других и оставался при этом ситуативно осведомлённым о том, что ещё происходит. В краткосрочной перспективе это ключевой фактор, определяющий производительность команды.

Ежедневные задачи:
- Установление и исполнение «рабочего ритма» команды, то есть набора повторяющихся встреч/ритуалов, которые помогают выполнять работу (стендапы, встречи по планированию/приоритизации, ретроспективы и т. д.)
- Выяснение, как разделить работу в команде, делегирование и мониторинг прогресса, чтобы убедиться, что задача не «застряла».
- Поддержание ориентации команды путём обеспечения «видимости» работы, например, с помощью каналов Slack или трекера задач и т. д.
- Обеспечение контакта между командой и остальной частью компании.

Управление проектами — это не просто административная задача; для его успешного выполнения требуется значительный объём экспертных знаний в предметной области (чтобы следить за обсуждениями проекта, понимать обновления статуса, отслеживать зависимости и т. д.). Помимо этого, полезно быть организованным и ориентированным на детали, а также иметь хорошие ментальные модели людей:
- Кто будет хорош в каких типах работы?
- Какие виды координационных ритуалов полезны для этой команды?

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

Когда команды становятся большими, управление проектами проще всего делегировать и разделить. Команду в 10+ человек лучше разделить, дать им разные области проекта и отдельных менеджеров проекта.

4. Техническое руководство
Означает ответственность за качество технической работы команды.

Конкретная работа включает:
- Установку технического направления (например, программы исследований на тему или разработку архитектуры системы).
- Проверку выполнения в соответствии с этим направлением (проверку экспериментальных проектов и результатов, технических проектных документов, проверку кода и т. д.)
- Другое техническое наставничество, например, личный менторинг, парное взаимодействие и т. д.
- Частично индивидуальное выполнение, хотя это может варьироваться в зависимости от того, насколько занят технический руководитель.

На практике многие команды имеют достаточно широкую область действия, чтобы в итоге иметь несколько технических руководителей в разных областях — разделенных либо «вертикально» по проекту, либо «горизонтально» по набору навыков, либо частично и так, и так.

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

Когда техническое руководство не на должном уровне, это чаще всего проявляется в виде накопления долгов или других проблем, которые замедляют выполнение: фиктивные результаты исследований, неинформативные эксперименты, нестабильные системы, частые сбои и т. д.

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

Источник:
https://www.benkuhn.net/leadcats/
👍8
День 2059. #Карьера
Категории Руководства в Технических Командах. Окончание

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

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

«Менеджер – техлид»
Когда новая компания вводит своих первых технических менеджеров, они часто делают это, переводя своего самого сильного технического специалиста(-ов) на руководящую должность и ожидая, что они выполнят все обязанности техлида (см. п.4). Некоторые прекрасно справляются с такими ролями, но чаще всего новый менеджер не очень хорош в одной или нескольких обязанностях — чаще всего в управлении людьми — и испытывает трудности из-за количества других вещей, за которые он отвечает.

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

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

Продукт-менеджер / техлид
Это разделение менее распространено. ПМ должны действовать как «мини-гендиректора» продуктовой области с довольно широкой автономией для работы в этой области. Поскольку эта роль включает множество компетенций, им не нужно быть такими же технически подкованными, как обычному ИМ.

Это сработает, если у ПМ и ТЛ каждой команды крепкие рабочие отношения, так что они могут эффективно общаться о таких вещах, как компромиссы между скоростью и техническим качеством, а не просто делать, как хочет ПМ.

Менеджер по персоналу/руководитель исследований
В этом разделении, в отличие от разделения ИМ/ТЛ в инженерной команде, разумнее, чтобы руководитель исследования отвечал за общее направление, поскольку оно в значительной степени зависит от высококонтекстных интуитивных суждений о том, в каком направлении исследования следовать. Во многих (хотя и не во всех!) инженерных командах приоритеты в меньшей степени зависят от такого рода высокотехнических суждений.

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

Источник:
https://www.benkuhn.net/leadcats/
👍2
День 2060. #Оффтоп
Вы Думаете Ваша Кодовая База Плохая?
Вот откровения разработчика СУБД Oracle 12.2.

Около 25 миллионов строк кода на C…

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

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

Иногда нужно понимать значения и эффект от 20 различных флагов, чтобы предсказать, как код будет вести себя в разных ситуациях. Иногда сотни! Я не преувеличиваю.

Единственная причина, по которой этот продукт все ещё выживает и все ещё работает, — это в буквальном смысле миллионы тестов!

Вот какова жизнь разработчика СУБД Oracle:
- Начинаете работать над новой ошибкой.

- Тратите пару недель на то, чтобы понять смысл 20 различных флагов, которые взаимодействуют загадочным образом, что приводит к ошибке.

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

- Отправляете изменения в тестовую ферму, состоящую примерно из 100-200 серверов, которые скомпилируют код, создадут новую базу данных Oracle и запустят миллионы тестов распределённым образом.

- Идёте домой. Приходите на следующий день и работайте над чем-то другим. Тесты могут занять от 20 до 30 часов.

- Идёте домой. Приходите на следующий день и проверяете результаты тестирования фермы. В хороший день будет около 100 неудачных тестов. В плохой день - около 1000. Выбираете некоторые из этих тестов случайным образом и пытайтесь понять, что пошло не так с вашими предположениями. Возможно, нужно рассмотреть ещё около 10 флагов, чтобы по-настоящему понять природу ошибки.

- Добавляете ещё несколько флагов, чтобы попытаться исправить проблему. Отправляете изменения ещё раз на тестирование. Ждёте ещё 20–30 часов.

- Так правите и повторяете ещё недели две, пока не получаете правильное таинственное заклинание из комбинации флагов.

- Наконец, в один прекрасный день вы добиваетесь успеха, и ни один тест не падает.

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

- Отправляете работу на последний раунд тестирования. Затем отправляете её на проверку. Сама проверка может занять ещё от 2 недель до 2 месяцев. Так что теперь вы переходите к следующей ошибке, над которой нужно работать.

- Недели через 2 (или месяца через 2), когда всё будет готово, код будет окончательно объединён с основной веткой.

Вышеизложенное — это не преувеличенное описание жизни программиста в Oracle, исправляющего ошибку. Теперь представьте, каким ужасом будет разработка новой функции. Разработка одной небольшой функции (например, добавления нового режима аутентификации, типа поддержки аутентификации AD) занимает от 6 месяцев до года (иногда 2 года!).

Тот факт, что этот продукт вообще работает, — просто чудо!

Я больше не работаю в Oracle. Никогда больше не буду работать в Oracle!

Источник: https://news.ycombinator.com/item?id=18442941
👍28
День 2061. #УрокиРазработки
Уроки 50 Лет Разработки ПО

Урок 24. Не давайте оценок наугад
Вы — бизнес-аналитик или владелец продукта. По дороге на работу вы встречаете представительницу клиентов вашего проекта:
- Я хотела бы добавить кое-что в наш проект», — говорит она. Вы выслушиваете её описание.
- Как думаете, сколько времени потребуется, чтобы сделать это?
- Около трех дней.
- Отлично, спасибо!

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

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

«По нашим оценкам, это займёт Х» часто воспринимается как «Мы обязуемся закончить через Х». Оценки и обязательства важны, но не следует путать их.

Часто есть соблазн дать быструю оценку, но старайтесь подавлять это искушение. Быстрые ответы не основаны на анализе, это догадки. Убедитесь, что точно знаете, о чём вопрос, затем оцените, что реально потребуется для решения. После анализа часто оказывается, что проблема более обширная, чем предполагалось. Если вы дадите реалистичную оценку, заказчик может отказаться от запроса. Лучше узнать об этом до того, как вы начнёте реализовывать новую функциональность, чем отказаться от неё, когда она уже будет наполовину проработана и вдруг выяснится, что изменение оказалось неоправданно большим.

Вопросы для оценки
- Какие предположения повлияли на оценку? Как можно проверить их достоверность?
- Известно ли, кто будет выполнять эту работу? У разных членов команды разные навыки; не все одинаково продуктивны. Если вы не знаете, кто справится с работой, считайте некий средний уровень производительности.
- Кто будет писать и выполнять тесты, ревью кода, регрессионное тестирование и т.п.? Касается ли ваша оценка всего объёма работ или только собственно разработки.
- Учли ли вы неочевидные последствия и дополнительную работу, которая может потребоваться помимо реализации новой функциональности? Она может повлиять на другие функции, негативно отразиться на некоторых атрибутах качества. Может понадобиться изменить дизайн или интерфейс либо обновить документацию.
- Есть ли риски или вы просчитали только идеальный сценарий?

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

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

Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 4.
👍12👎1
Вам нужно "округлить" заданное положительное целое число до ближайшей степени двойки, например, 3 -> 4, 10 -> 16, 191 -> 256. Что вы используете в C#?
Anonymous Quiz
5%
цикл
44%
комбинацию битовых сдвигов вправо (>>)
23%
комбинацию методов Math.Pow и Math.Log2
28%
метод RoundUpToPowerOf2
👍12👎3
День 2062. #Оффтоп
Сегодня посоветую вам видео из серии Deep .NET «Let's Build Our Own ArrayPool».

Скотт Хансельман спрашивает, а Стивен Тауб объясняет, как работает ArrayPool (да и прочие виды пулов) в .NET, когда его стоит и не стоит использовать, а также создаёт упрощённую реализацию пула массивов.

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

ЗЫ: и на тему вчерашнего опроса там тоже есть)))
👍18
День 2063. #ЧтоНовенького
.NET 9 RC1: Приближаемся к Релизу

Microsoft выпустили первый релиз-кандидат .NET 9, которая включает ряд обновлений основных компонентов, таких как .NET Runtime, SDK, библиотеки, C#, а также ASP.NET Core и .NET MAUI.

1. В ClientWebSocketOptions и WebSocketCreationOptions добавлены новые API, позволяющие разработчикам настраивать пинги WebSocket и автоматически завершать соединения, если в течение указанного периода времени не получен ответ:
using var cws = new ClientWebSocket();
cws.Options.HttpVersionPolicy =
HttpVersionPolicy.RequestVersionOrHigher;
cws.Options.KeepAliveInterval =
TimeSpan.FromSeconds(5);
cws.Options.KeepAliveTimeout =
TimeSpan.FromSeconds(1);


2. Добавлены новые типы — ZLibCompressionOptions и BrotliCompressionOptions, которые обеспечивают больший контроль над уровнями и стратегиями сжатия. Эти дополнения обеспечивают большую гибкость по сравнению с предыдущей опцией CompressionLevel.

3. Для работающих с TAR-архивами, в System.Formats.Tar.TarEntry добавлено свойство DataOffset, позволяющее получить доступ к положению данных в потоке. Это упрощает управление большими файлами TAR, включая функции одновременного доступа.

4. Начиная с этой версии, события LogLevel.Trace, сгенерированные HttpClientFactory, теперь по умолчанию исключают значения заголовков. Разработчики могут регистрировать определённые значения заголовков с помощью вспомогательного метода RedactLoggedHeaders, что повышает конфиденциальность и безопасность:
services.AddHttpClient("myClient")
.RedactLoggedHeaders(name => name != "User-Agent");


5. Добавлена команда dotnet workload history. Она отслеживает историю установок или изменений рабочей нагрузки в установке .NET SDK, предлагая информацию об изменениях версии рабочей нагрузки с течением времени. Она предназначена для того, чтобы помочь пользователям более эффективно управлять версиями рабочей нагрузки аналогично функциональности reflog в Git.

6. В ASP.NET Core представлены такие обновления, как:
- тайм-аут keep-alive для WebSockets
app.UseWebSockets(new WebSocketOptions { 
KeepAliveTimeout = TimeSpan.FromSeconds(15) });

- поддержка FromKeyedServices в промежуточном ПО как в конструкторе, так и в Invoke/InvokeAsync
- улучшения распределённой трассировки SignalR, направленные на повышение производительности и упрощение разработки.

7. Что касается .NET MAUI, релиз фокусируется на решении проблем и стабильности платформы. Среди новых функций:
- HorizontalTextAlignment.Justify предоставляет дополнительные параметры выравнивания текста для меток.
- обновления HybridWebView, особенно при вызове методов JavaScript из C#.

Источник: https://www.infoq.com/news/2024/09/dotnet-9-release-candidate-1/
👍12