День 2061. #УрокиРазработки
Уроки 50 Лет Разработки ПО
Урок 24. Не давайте оценок наугад
Вы — бизнес-аналитик или владелец продукта. По дороге на работу вы встречаете представительницу клиентов вашего проекта:
- Я хотела бы добавить кое-что в наш проект», — говорит она. Вы выслушиваете её описание.
- Как думаете, сколько времени потребуется, чтобы сделать это?
- Около трех дней.
- Отлично, спасибо!
На рабочем месте вы начинаете обдумывать просьбу и обнаруживаете множество сложностей. Вы понимаете, что команда не сможет реализовать её за три дня, как вы пообещали. Более того, она может конфликтовать с другой функцией. Не слишком ли поздно изменить ответ, который вы дали клиентам?
Поспешные прогнозы
Лучший ответ на вопрос, требующий оценки: «Я обдумаю и отвечу позже». Быстрая оценка на основе ограниченной информации и поверхностного анализа, может оказаться ужасающе неточной, но она очень похожа на обязательство перед другим человеком. Теперь вы должны объяснить, что на удовлетворение просьбы уйдёт больше времени. Потребуются переговоры и пересмотр планов, прежде чем команда сможет принять решение о добавлении этой новой функции. Может состояться неловкий разговор.
«По нашим оценкам, это займёт Х» часто воспринимается как «Мы обязуемся закончить через Х». Оценки и обязательства важны, но не следует путать их.
Часто есть соблазн дать быструю оценку, но старайтесь подавлять это искушение. Быстрые ответы не основаны на анализе, это догадки. Убедитесь, что точно знаете, о чём вопрос, затем оцените, что реально потребуется для решения. После анализа часто оказывается, что проблема более обширная, чем предполагалось. Если вы дадите реалистичную оценку, заказчик может отказаться от запроса. Лучше узнать об этом до того, как вы начнёте реализовывать новую функциональность, чем отказаться от неё, когда она уже будет наполовину проработана и вдруг выяснится, что изменение оказалось неоправданно большим.
Вопросы для оценки
- Какие предположения повлияли на оценку? Как можно проверить их достоверность?
- Известно ли, кто будет выполнять эту работу? У разных членов команды разные навыки; не все одинаково продуктивны. Если вы не знаете, кто справится с работой, считайте некий средний уровень производительности.
- Кто будет писать и выполнять тесты, ревью кода, регрессионное тестирование и т.п.? Касается ли ваша оценка всего объёма работ или только собственно разработки.
- Учли ли вы неочевидные последствия и дополнительную работу, которая может потребоваться помимо реализации новой функциональности? Она может повлиять на другие функции, негативно отразиться на некоторых атрибутах качества. Может понадобиться изменить дизайн или интерфейс либо обновить документацию.
- Есть ли риски или вы просчитали только идеальный сценарий?
Страх неопределённости
Иногда люди, получающие оценки, не осознают, насколько неопределённой может быть даже тщательно продуманная оценка. Чем более неопределённо сформулирована задача и чем менее чётко определены допущения, тем более расплывчатой будет оценка. Если клиенты услышат Х, то запомнят и будут строить свои планы, исходя из этого срока. Оценка в виде диапазона — от лучшего до худшего сценария — говорит, что это приблизительный прогноз, а не гарантия.
Поверхностное суждение чаще всего будет более оптимистичным и, следовательно, воспримется более благосклонно, но приведёт к большему разочарованию, когда проявится реальность. Нам нравится доставлять радость, когда кто-то о чём-то нас просит. Однако если вы потратите время на размышления о проблеме, прежде чем озвучить оценку её решения, то не окажетесь в неудобном положении.
Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 4.
Уроки 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, когда его стоит и не стоит использовать, а также создаёт упрощённую реализацию пула массивов.
Иногда Стивен уходит совсем в дебри и тонкости перемещения битиков, тогда Скотт старается вернуть его в реальность простых смертных. В общем, хорошее познавательное видео про кишочки дотнета, скоротать время в воскресенье.
ЗЫ: и на тему вчерашнего опроса там тоже есть)))
  
  Сегодня посоветую вам видео из серии Deep .NET «Let's Build Our Own ArrayPool».
Скотт Хансельман спрашивает, а Стивен Тауб объясняет, как работает ArrayPool (да и прочие виды пулов) в .NET, когда его стоит и не стоит использовать, а также создаёт упрощённую реализацию пула массивов.
Иногда Стивен уходит совсем в дебри и тонкости перемещения битиков, тогда Скотт старается вернуть его в реальность простых смертных. В общем, хорошее познавательное видео про кишочки дотнета, скоротать время в воскресенье.
ЗЫ: и на тему вчерашнего опроса там тоже есть)))
YouTube
  
  Deep .NET: Let's Build Our Own ArrayPool  with Stephen Toub and Scott Hanselman
  Stephen is back with Scott going DEEP with .NET! This time they are building their own ArrayPool from scratch explaining how it actually works. Then they go deeper into the built in ArrayPool of .NET and why you need it in your life!
Chapters:
00:00:00 Intro…
Chapters:
00:00:00 Intro…
👍18
  День 2063. #ЧтоНовенького
.NET 9 RC1: Приближаемся к Релизу
Microsoft выпустили первый релиз-кандидат .NET 9, которая включает ряд обновлений основных компонентов, таких как .NET Runtime, SDK, библиотеки, C#, а также ASP.NET Core и .NET MAUI.
1. В ClientWebSocketOptions и WebSocketCreationOptions добавлены новые API, позволяющие разработчикам настраивать пинги WebSocket и автоматически завершать соединения, если в течение указанного периода времени не получен ответ:
2. Добавлены новые типы — ZLibCompressionOptions и BrotliCompressionOptions, которые обеспечивают больший контроль над уровнями и стратегиями сжатия. Эти дополнения обеспечивают большую гибкость по сравнению с предыдущей опцией CompressionLevel.
3. Для работающих с TAR-архивами, в System.Formats.Tar.TarEntry добавлено свойство DataOffset, позволяющее получить доступ к положению данных в потоке. Это упрощает управление большими файлами TAR, включая функции одновременного доступа.
4. Начиная с этой версии, события LogLevel.Trace, сгенерированные HttpClientFactory, теперь по умолчанию исключают значения заголовков. Разработчики могут регистрировать определённые значения заголовков с помощью вспомогательного метода RedactLoggedHeaders, что повышает конфиденциальность и безопасность:
5. Добавлена команда dotnet workload history. Она отслеживает историю установок или изменений рабочей нагрузки в установке .NET SDK, предлагая информацию об изменениях версии рабочей нагрузки с течением времени. Она предназначена для того, чтобы помочь пользователям более эффективно управлять версиями рабочей нагрузки аналогично функциональности reflog в Git.
6. В ASP.NET Core представлены такие обновления, как:
- тайм-аут keep-alive для WebSockets
- поддержка FromKeyedServices в промежуточном ПО как в конструкторе, так и в Invoke/InvokeAsync
- улучшения распределённой трассировки SignalR, направленные на повышение производительности и упрощение разработки.
7. Что касается .NET MAUI, релиз фокусируется на решении проблем и стабильности платформы. Среди новых функций:
- HorizontalTextAlignment.Justify предоставляет дополнительные параметры выравнивания текста для меток.
- обновления HybridWebView, особенно при вызове методов JavaScript из C#.
Источник: https://www.infoq.com/news/2024/09/dotnet-9-release-candidate-1/
.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
  День 2064. #ЗаметкиНаПолях
Частичные Классы в C#
Частичные классы находятся в одном пространстве имён и имеют одинаковое имя класса. Их можно использовать для разделения функциональности между несколькими файлами.
Если вы создадите два класса MyClass в одном пространстве имён, вы получите ошибку компиляции:
CS0101: The namespace 'x' already contains a definition for 'MyClass'. You can't have two classes of the same namespace and class name. (Пространство имён 'x' уже содержит определение для 'MyClass'. У вас не может быть двух классов с одинаковым пространством имён и именем класса.)
Можно пометить их как частичные. Тогда компилятор объединит все элементы из каждого из частичных классов в один класс:
Ключевое слово partial также работает для структур, записей и интерфейсов.
Правила для частичных классов
1. Все классы должны иметь ключевое слово partial перед объявлением класса
Ключевое слово partial должно быть перед ключевым словом class (struct, record или interface). Если вы попытаетесь добавить abstract после partial, возникнет исключение:
CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. (Модификатор 'partial' может появляться только непосредственно перед 'class', 'record', 'struct', 'interface' или возвращаемым типом метода.)
2. Пространства имён должны быть одинаковыми
Если это не так, компилятор расценит объявление как другой класс и выдаст исключение, если вы используете любой из членов класса из другого пространства имён.
3. Модификаторы доступа должны быть одинаковыми
Если изменить один из частичных классов на internal, а другой оставить public, получится ошибка компиляции:
CS0262: Partial declarations of 'MyClass' have conflicting accessibility modifiers (Объявления частичного класса 'MyClass' имеют конфликтующие модификаторы доступа)
4. Абстрактные и запечатанные классы и атрибуты
Если один из частичных классов помечен как абстрактный, класс будет абстрактным, даже если он не объявлен абстрактным в других случаях. То же касается ключевого слова sealed. Попытка создать экземпляр абстрактного частичного класса выдаст ошибку компиляции.
Атрибуты класса следуют тому же правилу. Например, если пометить одно из объявлений частичного класса атрибутом [Obsolete], весь класс будет объявлен как устаревший.
5. Можно наследовать только один класс
Если в разных объявлениях частичного класса вы наследуете разные классы, вы получите следующее исключение:
CS0263: Partial declarations of 'MyClass' must not specify different base classes (Объявления частичного класса 'MyClass' не должны указывать разные базовые классы)
Однако в разных объявлениях можно указывать наследование от одного и того же класса.
Окончание следует…
Источник: https://www.roundthecode.com/dotnet-tutorials/what-are-partial-classes-csharp-why-do-we-use-them
Частичные Классы в C#
Частичные классы находятся в одном пространстве имён и имеют одинаковое имя класса. Их можно использовать для разделения функциональности между несколькими файлами.
Если вы создадите два класса MyClass в одном пространстве имён, вы получите ошибку компиляции:
CS0101: The namespace 'x' already contains a definition for 'MyClass'. You can't have two classes of the same namespace and class name. (Пространство имён 'x' уже содержит определение для 'MyClass'. У вас не может быть двух классов с одинаковым пространством имён и именем класса.)
Можно пометить их как частичные. Тогда компилятор объединит все элементы из каждого из частичных классов в один класс:
public partial class MyClass
{
public bool Ok { get; set; }
}
public partial class MyClass
{
public bool IsItOk()
{
return Ok;
}
}
Ключевое слово partial также работает для структур, записей и интерфейсов.
Правила для частичных классов
1. Все классы должны иметь ключевое слово partial перед объявлением класса
Ключевое слово partial должно быть перед ключевым словом class (struct, record или interface). Если вы попытаетесь добавить abstract после partial, возникнет исключение:
CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. (Модификатор 'partial' может появляться только непосредственно перед 'class', 'record', 'struct', 'interface' или возвращаемым типом метода.)
2. Пространства имён должны быть одинаковыми
Если это не так, компилятор расценит объявление как другой класс и выдаст исключение, если вы используете любой из членов класса из другого пространства имён.
3. Модификаторы доступа должны быть одинаковыми
Если изменить один из частичных классов на internal, а другой оставить public, получится ошибка компиляции:
CS0262: Partial declarations of 'MyClass' have conflicting accessibility modifiers (Объявления частичного класса 'MyClass' имеют конфликтующие модификаторы доступа)
4. Абстрактные и запечатанные классы и атрибуты
Если один из частичных классов помечен как абстрактный, класс будет абстрактным, даже если он не объявлен абстрактным в других случаях. То же касается ключевого слова sealed. Попытка создать экземпляр абстрактного частичного класса выдаст ошибку компиляции.
Атрибуты класса следуют тому же правилу. Например, если пометить одно из объявлений частичного класса атрибутом [Obsolete], весь класс будет объявлен как устаревший.
5. Можно наследовать только один класс
Если в разных объявлениях частичного класса вы наследуете разные классы, вы получите следующее исключение:
CS0263: Partial declarations of 'MyClass' must not specify different base classes (Объявления частичного класса 'MyClass' не должны указывать разные базовые классы)
public class MyBaseClass {…}
public class MyBaseClass2 {…}
public partial class MyClass : MyBaseClass //CS0263
{ … }
public partial class MyClass : MyBaseClass2
{ … }Однако в разных объявлениях можно указывать наследование от одного и того же класса.
Окончание следует…
Источник: https://www.roundthecode.com/dotnet-tutorials/what-are-partial-classes-csharp-why-do-we-use-them
👍13
  День 2065. #ЗаметкиНаПолях
Частичные Классы в C#. Окончание
Начало
6. Можно реализовать несколько интерфейсов
И не важно, в каком объявлении будет реализация интерфейса, главное, чтобы все интерфейсы были реализованы:
7. Конструкторы должны иметь разные сигнатуры
Не может быть нескольких конструкторов с одинаковой сигнатурой, даже если они появляются в разных частичных классах. Иначе будет ошибка компиляции
CS0111: Type 'MyClass' already defines a member called 'MyClass' with the same parameter types (Тип 'MyClass' уже определяет член с именем 'MyClass' с теми же типами параметров).
Частичные члены класса
Можно добавлять частичные члены в частичный класс. Это может быть удобно, если генератор исходного кода добавляет частичный метод, то есть вы можете добавить реализацию этого метода в другой частичный класс.
В следующем примере один из частичных классов добавляет частичный метод с именем Abc без реализации. Вы можете добавить эту реализацию в другой частичный класс:
Зачем использовать?
Частичные классы хороши, если над одним классом работают несколько разработчиков. Один разработчик может работать над одним файлом, а другой — над другим. Это поможет избежать конфликтов слияния при коммите файлов в систему управления исходным кодом. Также частичные классы позволяют добавлять дополнительную функциональность в классы, созданные генератором исходного кода.
Источник: https://www.roundthecode.com/dotnet-tutorials/what-are-partial-classes-csharp-why-do-we-use-them
Частичные Классы в C#. Окончание
Начало
6. Можно реализовать несколько интерфейсов
И не важно, в каком объявлении будет реализация интерфейса, главное, чтобы все интерфейсы были реализованы:
public interface IBase {
  void MyMethod();
}
public interface IBase2 {}
public partial class MyClass : IBase
{…}
public partial class MyClass : IBase2
{
  …  
  public MyMethod()
  {
    // …
  }
}7. Конструкторы должны иметь разные сигнатуры
Не может быть нескольких конструкторов с одинаковой сигнатурой, даже если они появляются в разных частичных классах. Иначе будет ошибка компиляции
CS0111: Type 'MyClass' already defines a member called 'MyClass' with the same parameter types (Тип 'MyClass' уже определяет член с именем 'MyClass' с теми же типами параметров).
public partial class MyClass
{
public MyClass() {…}
}
public partial class MyClass
{
public MyClass() {…} //CS0111
}
Частичные члены класса
Можно добавлять частичные члены в частичный класс. Это может быть удобно, если генератор исходного кода добавляет частичный метод, то есть вы можете добавить реализацию этого метода в другой частичный класс.
В следующем примере один из частичных классов добавляет частичный метод с именем Abc без реализации. Вы можете добавить эту реализацию в другой частичный класс:
public partial class MyClass
{
partial void Abc();
}
public partial class MyClass
{
partial void Abc()
{
// Реализация
}
}
Зачем использовать?
Частичные классы хороши, если над одним классом работают несколько разработчиков. Один разработчик может работать над одним файлом, а другой — над другим. Это поможет избежать конфликтов слияния при коммите файлов в систему управления исходным кодом. Также частичные классы позволяют добавлять дополнительную функциональность в классы, созданные генератором исходного кода.
Источник: https://www.roundthecode.com/dotnet-tutorials/what-are-partial-classes-csharp-why-do-we-use-them
👍6
  День 2066. #ЗаметкиНаПолях 
Использование Mutex<T> для Синхронизации Доступа к Общему Ресурсу
Когда вам нужно получить доступ к общему ресурсу, вы можете использовать оператор lock или примитив синхронизации, такой как System.Threading.Mutex, для синхронизации доступа.
Однако в сложном коде его легко забыть:
Можно сделать это более явным и менее подверженным ошибкам, создав класс Mutex<T>, который инкапсулирует общий ресурс и примитив синхронизации:
Вот реализация класса Mutex<T> и его области MutexScope<T>:
Источник: https://www.meziantou.net/using-mutex-t-to-synchronize-access-to-a-shared-resource.htm
Использование Mutex<T> для Синхронизации Доступа к Общему Ресурсу
Когда вам нужно получить доступ к общему ресурсу, вы можете использовать оператор lock или примитив синхронизации, такой как System.Threading.Mutex, для синхронизации доступа.
Однако в сложном коде его легко забыть:
var obj = new object();
var value = 42;
lock (obj)
{
// Надо убедиться, что lock используется везде, где происходит доступ к ресурсу
Console.WriteLine(value);
}
// ⚠️ Здесь доступ получен без блокировки
value = 43;
Можно сделать это более явным и менее подверженным ошибкам, создав класс Mutex<T>, который инкапсулирует общий ресурс и примитив синхронизации:
var m = new Mutex<int>(42);
using (var scope = m.Acquire())
{
// доступ к ресурсу
Console.WriteLine(scope.Value);
// изменение ресурса
scope.Value = 43;
}
// ✔️ Вы не можете использовать общий ресурс вне области мьютекса
Вот реализация класса Mutex<T> и его области MutexScope<T>:
sealed class Mutex<T>
{
internal T _value;
private readonly Lock _lock = new();
public Mutex() { _value = default!; }
public Mutex(T initialValue)
=> _value = initialValue;
public MutexScope<T> Acquire()
{
_lock.Enter();
return new MutexScope<T>(this);
}
internal void Release()
=> _lock.Exit();
}
sealed class MutexScope<T>
: IDisposable
{
private readonly Mutex<T> mutex;
private bool disposed;
internal MutexScope(Mutex<T> mutex)
{
this.mutex = mutex;
}
public ref T Value
{
get
{
ObjectDisposedException
.ThrowIf(disposed, this);
return ref mutex._value!;
}
}
public void Dispose()
{
mutex.Release();
disposed = true;
}
}
Источник: https://www.meziantou.net/using-mutex-t-to-synchronize-access-to-a-shared-resource.htm
👍28👎2
  День 2067. #УрокиРазработки
Уроки 50 Лет Разработки ПО
Урок 25. Айсберги всегда больше, чем кажутся
Практически все проекты выходят за рамки первоначальной оценки после более тщательного анализа проблем и запросов на изменение во время разработки. Чем дольше длится проект, тем большего его роста можно ожидать. Требования, предъявляемые к крупным проектам, обычно увеличиваются на 1–3% в месяц во время разработки. Если в ваших планах не предусмотрен такой рост, то вы наверняка отстанете от графика.
Так же, как на поверхности воды находится меньшая часть айсберга, так и большая часть работы над программным проектом изначально может быть неочевидна. Итеративные подходы к разработке подтверждают, что истинный размер айсберга неочевиден на первый взгляд. Поскольку ПО поставляется частями, заинтересованные стороны будут просить добавить дополнительные функции. И чем больше они увидят, тем больше им захочется.
Резерв времени
Один из способов не отстать от графика — предусмотреть резерв времени на случай непредвиденных обстоятельств. Запас времени помогает справиться с неопределённостью. В противном случае первое поступившее новое требование, выявление первой заниженной оценки или возникновение первой непредвиденной задачи сорвут график.
Резерв времени можно рассчитать на основе предыдущего опыта выхода за плановые границы и наблюдавшегося роста требований. Запланированные резервы времени могут идти как в конце нескольких взаимозависимых этапов разработки (питающие буферы), так и в конце всего проекта (буфер проекта). При Agile-разработке предусматривайте небольшие резервы времени в каждой итерации. Они помогут удержать цикл итераций в нужном русле и не откладывать незавершённую работу на более поздние итерации. Также можно предусмотреть дополнительную резервную итерацию в конце проекта, предназначенную для реализации отложенных и дополнительных требований и другой задержавшейся работы.
Резерв времени не влияет на конечный результат, он лишь обеспечивает запас прочности, позволяя учитывать неизвестные, непредвиденные обстоятельства и неточности оценки. Удаление резерва из графика не удаляет эти переменные, а просто снижает вашу способность справляться с ними и при этом выполнять обязательства. Руководитель, предлагающий убрать резервы времени, делает несколько предположений:
- Информация, которой вы располагаете сегодня, понятна, точна и стабильна.
- Все оценки точны или любые неточности будут уравновешивать друг друга.
- Известно, кто будет работать над проектом, и состав команды не изменится (никто не заболеет, не уволится и т.п.).
- Члены команды не будут отвлекаться на работу по поддержке предыдущего продукта или другие посторонние работы.
- Все зависимости проекта и риски от внешних факторов будут устранены вовремя.
Эти предположения загоняют команду разработчиков в угол и почти гарантированно приведут к нарушению графика. Лучший способ обосновать добавление в график резерва времени — показать, как он рассчитывается на основе предыдущего опыта работы. Данные, показывающие, насколько обычно растёт объём требований в ваших проектах, помогут обосновать необходимость включения в проект резерва времени.
Резервы времени также помогут в контрактных обязательствах. Когда клиент по ходу проекта попросит о небольшом изменении, наличие резерва времени позволит вам положительно ответить на его просьбу без риска сорвать график.
Итого
Планирование возможных событий не изменит того, что произойдёт на самом деле, но поможет преодолеть все сложности, не нарушая планов. Если вы не знаете всего размера айсберга, то ожидайте, что он будет больше, чем кажется, и планируйте соответственно. Даже если реализация проекта пройдёт успешно и выделенные резервы времени не используются, можно передать продукт досрочно — от этого выиграют все.
Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 4.
Уроки 50 Лет Разработки ПО
Урок 25. Айсберги всегда больше, чем кажутся
Практически все проекты выходят за рамки первоначальной оценки после более тщательного анализа проблем и запросов на изменение во время разработки. Чем дольше длится проект, тем большего его роста можно ожидать. Требования, предъявляемые к крупным проектам, обычно увеличиваются на 1–3% в месяц во время разработки. Если в ваших планах не предусмотрен такой рост, то вы наверняка отстанете от графика.
Так же, как на поверхности воды находится меньшая часть айсберга, так и большая часть работы над программным проектом изначально может быть неочевидна. Итеративные подходы к разработке подтверждают, что истинный размер айсберга неочевиден на первый взгляд. Поскольку ПО поставляется частями, заинтересованные стороны будут просить добавить дополнительные функции. И чем больше они увидят, тем больше им захочется.
Резерв времени
Один из способов не отстать от графика — предусмотреть резерв времени на случай непредвиденных обстоятельств. Запас времени помогает справиться с неопределённостью. В противном случае первое поступившее новое требование, выявление первой заниженной оценки или возникновение первой непредвиденной задачи сорвут график.
Резерв времени можно рассчитать на основе предыдущего опыта выхода за плановые границы и наблюдавшегося роста требований. Запланированные резервы времени могут идти как в конце нескольких взаимозависимых этапов разработки (питающие буферы), так и в конце всего проекта (буфер проекта). При Agile-разработке предусматривайте небольшие резервы времени в каждой итерации. Они помогут удержать цикл итераций в нужном русле и не откладывать незавершённую работу на более поздние итерации. Также можно предусмотреть дополнительную резервную итерацию в конце проекта, предназначенную для реализации отложенных и дополнительных требований и другой задержавшейся работы.
Резерв времени не влияет на конечный результат, он лишь обеспечивает запас прочности, позволяя учитывать неизвестные, непредвиденные обстоятельства и неточности оценки. Удаление резерва из графика не удаляет эти переменные, а просто снижает вашу способность справляться с ними и при этом выполнять обязательства. Руководитель, предлагающий убрать резервы времени, делает несколько предположений:
- Информация, которой вы располагаете сегодня, понятна, точна и стабильна.
- Все оценки точны или любые неточности будут уравновешивать друг друга.
- Известно, кто будет работать над проектом, и состав команды не изменится (никто не заболеет, не уволится и т.п.).
- Члены команды не будут отвлекаться на работу по поддержке предыдущего продукта или другие посторонние работы.
- Все зависимости проекта и риски от внешних факторов будут устранены вовремя.
Эти предположения загоняют команду разработчиков в угол и почти гарантированно приведут к нарушению графика. Лучший способ обосновать добавление в график резерва времени — показать, как он рассчитывается на основе предыдущего опыта работы. Данные, показывающие, насколько обычно растёт объём требований в ваших проектах, помогут обосновать необходимость включения в проект резерва времени.
Резервы времени также помогут в контрактных обязательствах. Когда клиент по ходу проекта попросит о небольшом изменении, наличие резерва времени позволит вам положительно ответить на его просьбу без риска сорвать график.
Итого
Планирование возможных событий не изменит того, что произойдёт на самом деле, но поможет преодолеть все сложности, не нарушая планов. Если вы не знаете всего размера айсберга, то ожидайте, что он будет больше, чем кажется, и планируйте соответственно. Даже если реализация проекта пройдёт успешно и выделенные резервы времени не используются, можно передать продукт досрочно — от этого выиграют все.
Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 4.
👍8
  День 2069. #ЗаметкиНаПолях
Тестируем HttpClient, Вызывающий API
API можно тестировать с помощью WebApplicationFactory, как было рассмотрено здесь. Но что, если нужно «имитировать» вызовы HttpClient внутри тестов? Например, у вас нет контроля над API, но нужно протестировать реакцию приложения на получение определённого ответа от API.
Допустим, у нас такой минимальный API:
Мы используем HttpClient внутри GreeterService. Как нам теперь протестировать этот класс? Мы бы не хотели делать настоящие HTTP-запросы в тестах (по крайней мере, к внешним системам), поскольку они делают тест нестабильным и ненадёжным. Кроме того, сложно проверить, как наш сервис будет обрабатывать отказы API.
HttpMessageHandler / DelegatingHandler
DelegatingHandler — это «промежуточное ПО» для HttpClient. Каждый раз, когда вызывается SendAsync, этот обработчик будет вызываться. Обычно его используют для ведения журнала, аутентификации и т. д. Но мы также можем использовать его в тестовых сценариях!
Обработчик для нашего теста будет выглядеть следующим образом:
Теперь используем FakeDataHandler:
И следующий тест пройдёт:
Так мы можем настраивать ответы, также проверять, как наш сервис реагирует на неудачные ответы, эмулировав их. Кроме того, при этом вы не делаете ненужных запросов к API.
Источник: https://steven-giesel.com/blogPost/47e4a351-0f1b-4bb5-a3d5-0ce4d7c1fa61/how-to-test-httpclient-inside-api-tests
Тестируем HttpClient, Вызывающий API
API можно тестировать с помощью WebApplicationFactory, как было рассмотрено здесь. Но что, если нужно «имитировать» вызовы HttpClient внутри тестов? Например, у вас нет контроля над API, но нужно протестировать реакцию приложения на получение определённого ответа от API.
Допустим, у нас такой минимальный API:
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddHttpClient<GreeterService>(
o => o.BaseAddress =
new Uri("https://www.website.com"));
var app = builder.Build();
app.MapGet("/", async (GreeterService svc)
=> await svc.GetSomethingAsync());
app.Run();
public sealed class GreeterService
{
private readonly HttpClient _client;
public GreeterService(HttpClient client)
=> _client = client;
public async Task<string> GetSomethingAsync()
=> await _client.GetStringAsync("/api");
}
Мы используем HttpClient внутри GreeterService. Как нам теперь протестировать этот класс? Мы бы не хотели делать настоящие HTTP-запросы в тестах (по крайней мере, к внешним системам), поскольку они делают тест нестабильным и ненадёжным. Кроме того, сложно проверить, как наш сервис будет обрабатывать отказы API.
HttpMessageHandler / DelegatingHandler
DelegatingHandler — это «промежуточное ПО» для HttpClient. Каждый раз, когда вызывается SendAsync, этот обработчик будет вызываться. Обычно его используют для ведения журнала, аутентификации и т. д. Но мы также можем использовать его в тестовых сценариях!
Обработчик для нашего теста будет выглядеть следующим образом:
public class FakeDataHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage>
SendAsync(
HttpRequestMessage request,
CancellationToken ct)
{
if (request.RequestUri is
{ AbsoluteUri: "https://www.website.com/api" })
{
return Task.FromResult(
new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent("Hello World"),
});
}
return base.SendAsync(request, ct);
}
}
Теперь используем FakeDataHandler:
public ApiTests(
WebApplicationFactory<Program> factory)
{
_factory = factory.WithWebHostBuilder(s =>
s.ConfigureTestServices(sc =>
{
sc.AddTransient<FakeDataHandler>();
sc.ConfigureHttpClientDefaults(d =>
d.AddHttpMessageHandler<FakeDataHandler>());
}));
}
И следующий тест пройдёт:
[Fact]
public async Task ShouldGreet()
{
using var client = _factory.CreateClient();
var response = await client.GetStringAsync("/api");
Assert.NotNull(response);
Assert.Equal("Hello World", response);
}
Так мы можем настраивать ответы, также проверять, как наш сервис реагирует на неудачные ответы, эмулировав их. Кроме того, при этом вы не делаете ненужных запросов к API.
Источник: https://steven-giesel.com/blogPost/47e4a351-0f1b-4bb5-a3d5-0ce4d7c1fa61/how-to-test-httpclient-inside-api-tests
👍17
  День 2070. #ЗаметкиНаПолях
Экономим Память с RecyclableMemoryStream
Когда мы работаем с потоками, у нас могут быть процессы с большой нагрузкой на GC, что означает снижение производительности из-за трат на сборку мусора.
В Microsoft создали библиотеку RecyclableMemoryStream для обеспечения пула для объектов MemoryStream с целью повышения производительности приложения, особенно в области сборки мусора.
Когда мы работаем с большими потоками, библиотека повышает производительность, выделяя объекты в кучу 2-го поколения, что должно сделать сборку мусора менее частой.
Подробно работа RecyclableMemoryStream расписана по ссылке выше, а мы рассмотрим небольшой пример. Представьте, что мы хотим сериализовать и заархивировать большой объект, в нашем случае - большую коллекцию. Чтобы её сгенерировать используем Bogus. Полный код примера можете посмотреть тут. Важно, что коллекция содержит 50000 элементов, и будет иметь всегда одинаковые случайные данные, поскольку используется одно и то же начальное число для их генерации.
Затем мы сериализуем коллекцию в zip-поток. Вот пример с MemoryStream:
Теперь сравним с реализацией, использующей RecyclabeMemoryStreamManager:
Очень похоже, за исключением того, что вместо MemoryStream используется RecyclabeMemoryStreamManager.
Теперь измерим производительность. Генерируем коллекцию и создаём экземпляр RecyclabeMemoryStreamManager в глобальной настройке, измеряем только сериализацию и сжатие.
Как видите, у RecyclableMemoryStreamManager огромное преимущество в использовании памяти.
RecyclableMemoryStreamManager имеет множество настроек, провайдер EventSource для трекинга, а также хуки событий, куда вы можете добавлять свой код.
Источник: https://medium.com/@matias.paulo84/recyclablememorystream-vs-memorystream-c4aa341324a9
Экономим Память с RecyclableMemoryStream
Когда мы работаем с потоками, у нас могут быть процессы с большой нагрузкой на GC, что означает снижение производительности из-за трат на сборку мусора.
В Microsoft создали библиотеку RecyclableMemoryStream для обеспечения пула для объектов MemoryStream с целью повышения производительности приложения, особенно в области сборки мусора.
Когда мы работаем с большими потоками, библиотека повышает производительность, выделяя объекты в кучу 2-го поколения, что должно сделать сборку мусора менее частой.
Подробно работа RecyclableMemoryStream расписана по ссылке выше, а мы рассмотрим небольшой пример. Представьте, что мы хотим сериализовать и заархивировать большой объект, в нашем случае - большую коллекцию. Чтобы её сгенерировать используем Bogus. Полный код примера можете посмотреть тут. Важно, что коллекция содержит 50000 элементов, и будет иметь всегда одинаковые случайные данные, поскольку используется одно и то же начальное число для их генерации.
Затем мы сериализуем коллекцию в zip-поток. Вот пример с MemoryStream:
List<User> users = PersonGenerator.Generate();
using (var stream = new MemoryStream())
{
using (var gzip = new GZipStream(
stream, CompressionLevel.Optimal, true))
{
await JsonSerializer.SerializeAsync(gzip, users);
await gzip.FlushAsync();
}
}
Теперь сравним с реализацией, использующей RecyclabeMemoryStreamManager:
List<User> users = PersonGenerator.Generate();
var msMgr = new RecyclableMemoryStreamManager();
using (var stream = msMgr.GetStream("memory"))
{
using (var gzip = new GZipStream(
stream, CompressionLevel.Optimal, true))
{
await JsonSerializer.SerializeAsync(gzip, users);
await gzip.FlushAsync();
}
}
Очень похоже, за исключением того, что вместо MemoryStream используется RecyclabeMemoryStreamManager.
Теперь измерим производительность. Генерируем коллекцию и создаём экземпляр RecyclabeMemoryStreamManager в глобальной настройке, измеряем только сериализацию и сжатие.
| Method | Mean | Allocated |
| Recyclable | 496.1 ms | 37.59 KB |
| MemoryStream | 506.2 ms | 16422.09 KB |
Как видите, у RecyclableMemoryStreamManager огромное преимущество в использовании памяти.
RecyclableMemoryStreamManager имеет множество настроек, провайдер EventSource для трекинга, а также хуки событий, куда вы можете добавлять свой код.
Источник: https://medium.com/@matias.paulo84/recyclablememorystream-vs-memorystream-c4aa341324a9
👍27
  День 2071. #ЗаметкиНаПолях
Реалистичные Фейковые Данные с Помощью Bogus. Начало
Во вчерашнем посте я упомянул библиотеку Bogus для генерации случайных данных. Сегодня рассмотрим её поподробнее.
Иногда нужно поэкспериментировать с некоторыми функциями или создать демо проект, не создавая при этом реальный экземпляр БД. Также хотелось бы использовать более-менее реалистичные данные, а не «test1», 123 и т. д.
Bogus — популярная библиотека для генерации реалистичных данных для тестов. Она позволяет выбрать категорию фиктивных данных, которая лучше всего соответствует вашим потребностям.
Вы можете определить так называемые «фейкеры», целью которых является генерация фиктивных экземпляров классов путем автоматического заполнения их полей. Вот простой пример. Пусть у нас есть POCO-класс Book:
И нам необходимо создать коллекцию книг. Для начала создадим:
Мы можем добавить один или несколько методов RuleFor для создания правил, используемых для генерации каждого свойства. Самый простой подход — использовать перегрузку, где первый параметр — это функция, указывающая на заполняемое свойство, а второй — функция, которая вызывает методы, предоставляемые Bogus, для создания фиктивных данных. В виде псевдокода это выглядит так:
Другой вариант – использовать строковое имя свойства:
Также можно определить генератор для определённого типа данных, указав, например, что «каждый раз, когда надо создать данные для этого типа, используй этот генератор»:
Далее рассмотрим генерацию данных для основных типов.
Продолжение следует…
Источник: https://www.code4it.dev/blog/seed-inmemory-entityframework-bogus/
Реалистичные Фейковые Данные с Помощью Bogus. Начало
Во вчерашнем посте я упомянул библиотеку Bogus для генерации случайных данных. Сегодня рассмотрим её поподробнее.
Иногда нужно поэкспериментировать с некоторыми функциями или создать демо проект, не создавая при этом реальный экземпляр БД. Также хотелось бы использовать более-менее реалистичные данные, а не «test1», 123 и т. д.
Bogus — популярная библиотека для генерации реалистичных данных для тестов. Она позволяет выбрать категорию фиктивных данных, которая лучше всего соответствует вашим потребностям.
Вы можете определить так называемые «фейкеры», целью которых является генерация фиктивных экземпляров классов путем автоматического заполнения их полей. Вот простой пример. Пусть у нас есть POCO-класс Book:
public class Book
{
public Guid Id { get; set; }
public string Title { get; set; }
public int Pages { get; set; }
public Genre[] Genres { get; set; }
public DateOnly PublicationDate { get; set; }
public string Author { get; set; }
}
public enum Genre
{
Thriller, Fantasy, Romance, Biography
}
И нам необходимо создать коллекцию книг. Для начала создадим:
Faker<Book> bookFaker = new Faker<Book>();
Мы можем добавить один или несколько методов RuleFor для создания правил, используемых для генерации каждого свойства. Самый простой подход — использовать перегрузку, где первый параметр — это функция, указывающая на заполняемое свойство, а второй — функция, которая вызывает методы, предоставляемые Bogus, для создания фиктивных данных. В виде псевдокода это выглядит так:
faker.RuleFor(
sm => sm.SomeProperty,
f => f.DataGenerator.Generate());
Другой вариант – использовать строковое имя свойства:
faker.RuleFor(
"SomeProperty",
f => f.DataGenerator.Generate());
Также можно определить генератор для определённого типа данных, указав, например, что «каждый раз, когда надо создать данные для этого типа, используй этот генератор»:
bookFaker.RuleForType(
typeof(DateOnly),
f => f.Date.PastDateOnly());
Далее рассмотрим генерацию данных для основных типов.
Продолжение следует…
Источник: https://www.code4it.dev/blog/seed-inmemory-entityframework-bogus/
👍20
  День 2072. #ЗаметкиНаПолях
Реалистичные Фейковые Данные с Помощью Bogus. Продолжение
Начало
Генерация данных
1. Случайные ID
2. Случайный текст
Мы можем генерировать случайный текст по шаблону «Lorem Ipsum». Можно генерировать текст разной длины в буквах, словах, предложениях, параграфах и т.п.:
3. Перечисления
Для перечислений можно использовать свойство Random, чтобы получить несколько случайных значений перечисления (в данном случае – 2, если не задать параметр – случайное количество):
Если нужно получить одно значение, используйте
4. Фиктивные данные людей
Одной из самых захватывающих функций Bogus является возможность генерировать реалистичные данные для обычных сущностей, таких как люди. Можно использовать свойство Person для генерации данных человека: имени, фамилии, пола, логина, телефона, веб-сайта и других:
5. Генерация итогового класса
После определения правил мы можем сгенерировать реальные экземпляры. Нужно вызвать метод Generate, указав количество элементов для генерации:
Для генерации случайного количества элементов:
Вот полный пример генерации списка книг:
Окончание следует…
Источник: https://www.code4it.dev/blog/seed-inmemory-entityframework-bogus/
Реалистичные Фейковые Данные с Помощью Bogus. Продолжение
Начало
Генерация данных
1. Случайные ID
bookFaker.RuleFor(b => b.Id,
f => f.Random.Guid());
2. Случайный текст
Мы можем генерировать случайный текст по шаблону «Lorem Ipsum». Можно генерировать текст разной длины в буквах, словах, предложениях, параграфах и т.п.:
bookFaker.RuleFor(b => b.Title,
f => f.Lorem.Text());
3. Перечисления
Для перечислений можно использовать свойство Random, чтобы получить несколько случайных значений перечисления (в данном случае – 2, если не задать параметр – случайное количество):
bookFaker.RuleFor(b => b.Genres,
f => f.Random.EnumValues<Genre>(2));
Если нужно получить одно значение, используйте
f.Random.Enum<Genre>().4. Фиктивные данные людей
Одной из самых захватывающих функций Bogus является возможность генерировать реалистичные данные для обычных сущностей, таких как люди. Можно использовать свойство Person для генерации данных человека: имени, фамилии, пола, логина, телефона, веб-сайта и других:
bookFaker.RuleFor(b => b.Author,
f => $"{f.Person.FirstName} {f.Person.LastName}");
5. Генерация итогового класса
После определения правил мы можем сгенерировать реальные экземпляры. Нужно вызвать метод Generate, указав количество элементов для генерации:
List<Book> books = bookFaker.Generate(2);
Для генерации случайного количества элементов:
List<Book> books = bookFaker.GenerateBetween(2, 5);
Вот полный пример генерации списка книг:
private List<Book> GenerateBooks(int count)
{
Faker<Book> bookFaker = new Faker<Book>()
.RuleFor(b => b.Id,
f => f.Random.Guid())
.RuleFor(b => b.Title,
f => f.Lorem.Text())
.RuleFor(b => b.Genres,
f => f.Random.EnumValues<Genre>())
.RuleFor(b => b.Author,
f => $"{f.Person.FirstName} {f.Person.LastName}")
.RuleFor(nameof(Book.Pages),
f => f.Random.Number(100, 800))
.RuleForType(typeof(DateOnly),
f => f.Date.PastDateOnly());
return bookFaker.Generate(count);
}
Окончание следует…
Источник: https://www.code4it.dev/blog/seed-inmemory-entityframework-bogus/
👍12
  День 2073. #ЗаметкиНаПолях
Реалистичные Фейковые Данные с Помощью Bogus. Окончание
Начало
Продолжение
Заполнение БД в памяти фиктивными данными
Используем Entity Framework для БД в памяти. Для этого нужно установить NuGet-пакет Microsoft.EntityFrameworkCore.InMemory.
Теперь добавим класс DbContext и зададим БД в памяти:
Теперь можно заполнить БД данными, сгенерированными Bogus, переопределив метод OnModelCreating:
Здесь мы используем метод GenerateBooks, описанный во вчерашнем посте, и задаём полученный список книг в качестве содержимого набора данных Books.
Теперь можно прочитать данные из нашей БД:
Изучите все потенциальные возможности Bogus здесь. Это поможет сделать ваши тесты и эксперименты осмысленными и более понятными.
Итого
Bogus — отличная библиотека для создания модульных и интеграционных тестов. Генерировать фиктивные данные может быть полезно и в других различных сценариях, например, для создания заглушки сервиса, заполнения пользовательского интерфейса реалистичными данными или опробования других инструментов и функций.
Источник: https://www.code4it.dev/blog/seed-inmemory-entityframework-bogus/
Реалистичные Фейковые Данные с Помощью Bogus. Окончание
Начало
Продолжение
Заполнение БД в памяти фиктивными данными
Используем Entity Framework для БД в памяти. Для этого нужно установить NuGet-пакет Microsoft.EntityFrameworkCore.InMemory.
Теперь добавим класс DbContext и зададим БД в памяти:
public class BooksDbContext : DbContext
{
public DbSet<Book> Books { get; set; }
protected override void
OnConfiguring(DbContextOptionsBuilder builder)
{
builder.UseInMemoryDatabase("BooksDatabase");
}
}
Теперь можно заполнить БД данными, сгенерированными Bogus, переопределив метод OnModelCreating:
protected override void
OnModelCreating(ModelBuilder mb)
{
base.OnModelCreating(mb);
var books =
BogusBookGenerator.GenerateBooks(15);
mb.Entity<Book>().HasData(books);
}
Здесь мы используем метод GenerateBooks, описанный во вчерашнем посте, и задаём полученный список книг в качестве содержимого набора данных Books.
Теперь можно прочитать данные из нашей БД:
using var ctx = new BooksDbContext();
ctx.Database.EnsureCreated();
var allBooks = await ctx.Books.ToListAsync();
var thrillers = ctx.Books
.Where(b => b.Genres.Contains(Genre.Thriller))
.ToList();
Изучите все потенциальные возможности Bogus здесь. Это поможет сделать ваши тесты и эксперименты осмысленными и более понятными.
Итого
Bogus — отличная библиотека для создания модульных и интеграционных тестов. Генерировать фиктивные данные может быть полезно и в других различных сценариях, например, для создания заглушки сервиса, заполнения пользовательского интерфейса реалистичными данными или опробования других инструментов и функций.
Источник: https://www.code4it.dev/blog/seed-inmemory-entityframework-bogus/
👍14
  День 2074. #Карьера
Упрощатели Заходят Далеко, Усложнятели Застревают
«Если вы не можете объяснить это шестилетнему ребенку, вы сами этого не понимаете».
– Альберт Эйнштейн
В бизнесе есть два типа людей:
1. Упрощатели - делают сложные вещи простыми.
2. Усложнятели - делают простые вещи сложными.
Короткая шутка
- Как усложнятель называет упрощателя?
- Босс.
Где-то, когда-то некоторые люди решили, что в бизнесе нужно все усложнять и говорить на деловом жаргоне.
«Что ж, это интересное предложение, и я не обязательно против него, поэтому позвольте мне поднять его на флагшток, чтобы мы могли побить его палками, как пиньяту. Поскольку я слышал, что эта идея имеет некоторую поддержку в этой области, позвольте мне связаться с ребятами наверху, и мы посмотрим, хватит ли у нас ресурсов, чтобы продолжить работу над этим. Если стоимость выше $100 тыс., мне, возможно, придётся отложить эту идею, потому что нам нужно сохранить немного сухого пороха в ожидании результатов стратегической встречи — где, как я знаю, мы рассматриваем серьёзные изменения. Так что давайте оставаться на связи. Честь и хвала команде за то, что они придумали такое отличное ценностное предложение, но сейчас, боюсь, не могу его принять.»
Это один из способов спрятаться за сложностью: сделать себя совершенно непонятным. Хотя это может произвести впечатление на кого-то, ваши подчинённые будут высмеивать вас, а ваши начальники захотят поговорить с кем-то другим. При общении с руководителями нужно говорить чётко и, прежде всего, отвечать на вопросы. В большинстве организаций, хотя жаргон и двусмысленность могут быть распространены среди менеджеров среднего звена, они почти отсутствуют среди руководителей.
Другой способ спрятаться за сложностью — не лингвистический, а концептуальный: всегда находить проблему вышестоящего уровня или более масштабную проблему, которая будет блокировать прогресс на нижнем уровне. Рассмотрим такое утверждение:
«Я хотел бы перейти на новый процесс, но мы ещё не завершили обучение.»
Является ли это веской причиной для отсутствия прогресса в переходе на новый процесс или это пассивное сопротивление, замаскированное под причину? Например, я не хочу переходить на новый процесс, поэтому у меня постоянно «возникают проблемы» с планированием обучения. Или это добросовестное усложнение? Если обучение можно свести к одной странице, которую каждый может прочитать за 5 минут, то просто сократите его.
Есть старая поговорка:
«Когда вы спрашиваете время, некоторые люди скажут вам, как собрать часы. Другие расскажут вам, как построить целую швейцарскую деревню.»
Тест на выявление усложнятелей — это поиск следующих паттернов поведения:
- Медленный прогресс в достижении результатов
- Ссылки на сложность или запутанность
- Тенденция находить искусственные предварительные условия и осложнения, которые кажутся правдоподобными, но при дальнейшем рассмотрении таковыми не являются.
Вещи настолько сложны, насколько мы хотим их сделать. В большинстве случаев сложность — это оправдание либо нежелания что-то делать, либо незнания, как что-то делать.
Стремитесь делать вещи простыми. Стремитесь понять их. Боритесь за то, чтобы найти для них подходящие метафоры. Если вы не тратите энергию, пытаясь упростить вещи для своей аудитории, вы больше всего похожи на усложнятеля. Если так, то в следующий раз, когда вы соберётесь объяснить кому-то, почему что-то занимает так много времени, является таким сложным или требует выполнения 5 шагов перед началом, спросите себя: «Действительно ли я в это верю или я все усложняю, потому что либо не хочу, либо не знаю, как это сделать?»
Источник: https://kellblog.com/2015/05/13/career-advice-simplifiers-go-far-complexifiers-get-stuck/
Упрощатели Заходят Далеко, Усложнятели Застревают
«Если вы не можете объяснить это шестилетнему ребенку, вы сами этого не понимаете».
– Альберт Эйнштейн
В бизнесе есть два типа людей:
1. Упрощатели - делают сложные вещи простыми.
2. Усложнятели - делают простые вещи сложными.
Короткая шутка
- Как усложнятель называет упрощателя?
- Босс.
Где-то, когда-то некоторые люди решили, что в бизнесе нужно все усложнять и говорить на деловом жаргоне.
«Что ж, это интересное предложение, и я не обязательно против него, поэтому позвольте мне поднять его на флагшток, чтобы мы могли побить его палками, как пиньяту. Поскольку я слышал, что эта идея имеет некоторую поддержку в этой области, позвольте мне связаться с ребятами наверху, и мы посмотрим, хватит ли у нас ресурсов, чтобы продолжить работу над этим. Если стоимость выше $100 тыс., мне, возможно, придётся отложить эту идею, потому что нам нужно сохранить немного сухого пороха в ожидании результатов стратегической встречи — где, как я знаю, мы рассматриваем серьёзные изменения. Так что давайте оставаться на связи. Честь и хвала команде за то, что они придумали такое отличное ценностное предложение, но сейчас, боюсь, не могу его принять.»
Это один из способов спрятаться за сложностью: сделать себя совершенно непонятным. Хотя это может произвести впечатление на кого-то, ваши подчинённые будут высмеивать вас, а ваши начальники захотят поговорить с кем-то другим. При общении с руководителями нужно говорить чётко и, прежде всего, отвечать на вопросы. В большинстве организаций, хотя жаргон и двусмысленность могут быть распространены среди менеджеров среднего звена, они почти отсутствуют среди руководителей.
Другой способ спрятаться за сложностью — не лингвистический, а концептуальный: всегда находить проблему вышестоящего уровня или более масштабную проблему, которая будет блокировать прогресс на нижнем уровне. Рассмотрим такое утверждение:
«Я хотел бы перейти на новый процесс, но мы ещё не завершили обучение.»
Является ли это веской причиной для отсутствия прогресса в переходе на новый процесс или это пассивное сопротивление, замаскированное под причину? Например, я не хочу переходить на новый процесс, поэтому у меня постоянно «возникают проблемы» с планированием обучения. Или это добросовестное усложнение? Если обучение можно свести к одной странице, которую каждый может прочитать за 5 минут, то просто сократите его.
Есть старая поговорка:
«Когда вы спрашиваете время, некоторые люди скажут вам, как собрать часы. Другие расскажут вам, как построить целую швейцарскую деревню.»
Тест на выявление усложнятелей — это поиск следующих паттернов поведения:
- Медленный прогресс в достижении результатов
- Ссылки на сложность или запутанность
- Тенденция находить искусственные предварительные условия и осложнения, которые кажутся правдоподобными, но при дальнейшем рассмотрении таковыми не являются.
Вещи настолько сложны, насколько мы хотим их сделать. В большинстве случаев сложность — это оправдание либо нежелания что-то делать, либо незнания, как что-то делать.
Стремитесь делать вещи простыми. Стремитесь понять их. Боритесь за то, чтобы найти для них подходящие метафоры. Если вы не тратите энергию, пытаясь упростить вещи для своей аудитории, вы больше всего похожи на усложнятеля. Если так, то в следующий раз, когда вы соберётесь объяснить кому-то, почему что-то занимает так много времени, является таким сложным или требует выполнения 5 шагов перед началом, спросите себя: «Действительно ли я в это верю или я все усложняю, потому что либо не хочу, либо не знаю, как это сделать?»
Источник: https://kellblog.com/2015/05/13/career-advice-simplifiers-go-far-complexifiers-get-stuck/
👍13
  Как бы вы изменили реляционную модель, чтобы увеличить производительность запросов к базе данных?
#Quiz #DataModeling
  #Quiz #DataModeling
Anonymous Quiz
    39%
    Добавили бы избыточности в модель, тем самым уменьшив количество объединений в запросе
      
    15%
    Добавили бы представление с меньшим количеством колонок, чтобы упростить структуру запроса
      
    16%
    Убрали бы избыточность в модели, снизив количество хранимых данных, что ускоряет запросы
      
    30%
    Добавили бы целочисленный суррогатный ключ в каждую таблицу для более эффективного извлечения данных
      
    👍6👎1
  День 2075. #УрокиРазработки
Уроки 50 Лет Разработки ПО
Урок 26. Ваши переговорные позиции будут сильнее при наличии обосновывающих данных
Договариваясь о цене с продавцом в автосалоне подержанных авто, вы в невыгодном положении. Продавец имеет множество данных: о рынке цен на машины, о цене, по которой сдали это авто и о минимальной прибыли, которую нужно получить, о состоянии авто и т.п. У вас же, скорее всего, из информации будет только цена. Если вы не поленились и проведёте исследование рынка (а лучше и диагностику авто), то это вам поможет занять более сильную позицию.
Откуда вы взяли эту цифру?
Программный проект не имеет фиксированной цены, которую можно использовать в качестве отправной точки. Но та же ситуация может сложиться и на переговорах между заинтересованными сторонами.
Предположим, я — руководитель проекта. Клиент спрашивает, сколько времени потребуется и сколько это будет стоить. Основываясь на своём понимании проекта и опыте, я разрабатываю и представляю смету. Если спонсору не нравится моя оценка, возможны два исхода:
1) Я пытаюсь защитить свою оценку, не имея данных, а спонсор настаивает на сокращении затрат. Это не переговоры, а дебаты, которые я, скорее всего, проиграю.
2) Я, основываясь на данных, а не на эмоциях, описываю спонсору, как получена оценка, например:
- Я посоветовался с опытными членами команды, которые понимают, какого объёма работы требует новый проект.
- Мы оценили размер проекта на основе имеющейся информации и при этом учли фактор неопредёленности и ожидаемого разрастания, основываясь на прошлом опыте.
- Мы пересмотрели наш прошлый опыт работы с аналогичными проектами и т.д.
Если клиент по-прежнему не соглашается с оценкой, мы можем обсудить факты. Возможно, проект не похож ни на что сделанное нами ранее и наши исходные данные неактуальны. Это увеличивает риски и неопределённость оценок. Может, мы недостаточно хорошо понимаем проект, чтобы прийти к более реалистичной оценке. Придётся двигаться постепенно, оценивая каждый фрагмент по мере продвижения. Это снова порождает некую неопределенность в отношении сроков завершения проекта и его конечной стоимости. Однако наши базовые данные и процесс аналитической оценки послужат основой для сбалансированного обсуждения реального положения дел.
Принципиальные переговоры
Каждый раз, когда возникает разрыв между ожиданиями или требованиями заинтересованной стороны и вашим прогнозом в виде оценки, необходимо провести переговоры. Принципиальные переговоры — это метод достижения взаимоприемлемых соглашений. Они базируются на четырёх принципах:
1) Отделите людей от задач. Если обсуждение сводится к личной борьбе между вами и кем-то обладающим большей властью, то вы гарантированно проиграете, если не сможете привести убедительные доводы в свою пользу.
2) Сосредоточьтесь на интересах, а не на позициях. Не упорствуйте бездумно в защите своей оценки. Постарайтесь понять интересы другой стороны. Возможно, есть способ удовлетворить и их, и ваши интересы, изменив формулировку задачи или предлагаемое решение.
3) Придумывайте варианты для взаимной выгоды. Если вас вынуждают дать обещание, которое, как вы знаете, команда не сможет выполнить, ищите альтернативные взаимоприемлемые исходы с реалистичными целями, которых вы действительно сможете достичь. По результатам большинства успешных переговоров ни одна из сторон не получает всего, чего хочет, но обе стороны могут смириться с результатом — компромиссом.
4) Настаивайте на использовании объективных критериев. Здесь пригодятся ваши данные. Используйте данные для обоснования своих оценок и уважайте данные, представленные партнёром по переговорам.
Никто не может точно предсказать будущее. Лучшее, что можно сделать, — экстраполировать предыдущий опыт, внести коррективы там, где это оправданно, и признать неопределённость. Пусть за вас говорят данные, и предложите другой переговорной стороне поделиться своими данными. Возможно, так вы достигнете согласия и получите приемлемый результат.
Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 4.
Уроки 50 Лет Разработки ПО
Урок 26. Ваши переговорные позиции будут сильнее при наличии обосновывающих данных
Договариваясь о цене с продавцом в автосалоне подержанных авто, вы в невыгодном положении. Продавец имеет множество данных: о рынке цен на машины, о цене, по которой сдали это авто и о минимальной прибыли, которую нужно получить, о состоянии авто и т.п. У вас же, скорее всего, из информации будет только цена. Если вы не поленились и проведёте исследование рынка (а лучше и диагностику авто), то это вам поможет занять более сильную позицию.
Откуда вы взяли эту цифру?
Программный проект не имеет фиксированной цены, которую можно использовать в качестве отправной точки. Но та же ситуация может сложиться и на переговорах между заинтересованными сторонами.
Предположим, я — руководитель проекта. Клиент спрашивает, сколько времени потребуется и сколько это будет стоить. Основываясь на своём понимании проекта и опыте, я разрабатываю и представляю смету. Если спонсору не нравится моя оценка, возможны два исхода:
1) Я пытаюсь защитить свою оценку, не имея данных, а спонсор настаивает на сокращении затрат. Это не переговоры, а дебаты, которые я, скорее всего, проиграю.
2) Я, основываясь на данных, а не на эмоциях, описываю спонсору, как получена оценка, например:
- Я посоветовался с опытными членами команды, которые понимают, какого объёма работы требует новый проект.
- Мы оценили размер проекта на основе имеющейся информации и при этом учли фактор неопредёленности и ожидаемого разрастания, основываясь на прошлом опыте.
- Мы пересмотрели наш прошлый опыт работы с аналогичными проектами и т.д.
Если клиент по-прежнему не соглашается с оценкой, мы можем обсудить факты. Возможно, проект не похож ни на что сделанное нами ранее и наши исходные данные неактуальны. Это увеличивает риски и неопределённость оценок. Может, мы недостаточно хорошо понимаем проект, чтобы прийти к более реалистичной оценке. Придётся двигаться постепенно, оценивая каждый фрагмент по мере продвижения. Это снова порождает некую неопределенность в отношении сроков завершения проекта и его конечной стоимости. Однако наши базовые данные и процесс аналитической оценки послужат основой для сбалансированного обсуждения реального положения дел.
Принципиальные переговоры
Каждый раз, когда возникает разрыв между ожиданиями или требованиями заинтересованной стороны и вашим прогнозом в виде оценки, необходимо провести переговоры. Принципиальные переговоры — это метод достижения взаимоприемлемых соглашений. Они базируются на четырёх принципах:
1) Отделите людей от задач. Если обсуждение сводится к личной борьбе между вами и кем-то обладающим большей властью, то вы гарантированно проиграете, если не сможете привести убедительные доводы в свою пользу.
2) Сосредоточьтесь на интересах, а не на позициях. Не упорствуйте бездумно в защите своей оценки. Постарайтесь понять интересы другой стороны. Возможно, есть способ удовлетворить и их, и ваши интересы, изменив формулировку задачи или предлагаемое решение.
3) Придумывайте варианты для взаимной выгоды. Если вас вынуждают дать обещание, которое, как вы знаете, команда не сможет выполнить, ищите альтернативные взаимоприемлемые исходы с реалистичными целями, которых вы действительно сможете достичь. По результатам большинства успешных переговоров ни одна из сторон не получает всего, чего хочет, но обе стороны могут смириться с результатом — компромиссом.
4) Настаивайте на использовании объективных критериев. Здесь пригодятся ваши данные. Используйте данные для обоснования своих оценок и уважайте данные, представленные партнёром по переговорам.
Никто не может точно предсказать будущее. Лучшее, что можно сделать, — экстраполировать предыдущий опыт, внести коррективы там, где это оправданно, и признать неопределённость. Пусть за вас говорят данные, и предложите другой переговорной стороне поделиться своими данными. Возможно, так вы достигнете согласия и получите приемлемый результат.
Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 4.
👍14
  День 2076. #ЧтоНовенького
Организуем Точки Останова
Если в вашем проекте множество точек останова, новая функция группировки точек останова в Visual Studio 2022 поможет легко их классифицировать, включать и отключать по группам.
Группировка точек останова позволяет создавать пользовательские коллекции точек останова и применять к ним различные действия. Например, включать или отключать все точки останова в группе или задавать для них условия и действия или даже делать всю группу зависимой от других точек останова.
Также можно отметить выбранную группу точек останова как группу по умолчанию, гарантируя, что все вновь добавленные точки останова будут автоматически включаться в эту группу.
Чтобы создать группу точек останова, щелкните правой кнопкой мыши на любую точку останова в окне Breakpoints и выберите Add to Group > New Group (Добавить в группу > Новая группа). Вы можете назвать группу и добавить описание, если хотите. Добавлять точки останова в группу можно простым перетаскиванием или через контекстное меню.
Чтобы установить группу точек останова в качестве группы по умолчанию, просто щелкните правой кнопкой мыши по группе и выберите Set as Default Group (Установить как группу по умолчанию). Группа по умолчанию будет обозначена жирным шрифтом. Если у вас есть группа точек останова по умолчанию, все новые точки останова, которые вы добавляете в код, будут автоматически добавляться в эту группу.
Вы можете получить доступ ко всем действиям группы точек останова из контекстного меню или панели инструментов в окне Breakpoints.
Источник: https://devblogs.microsoft.com/visualstudio/organize-your-breakpoints-like-a-pro/
Организуем Точки Останова
Если в вашем проекте множество точек останова, новая функция группировки точек останова в Visual Studio 2022 поможет легко их классифицировать, включать и отключать по группам.
Группировка точек останова позволяет создавать пользовательские коллекции точек останова и применять к ним различные действия. Например, включать или отключать все точки останова в группе или задавать для них условия и действия или даже делать всю группу зависимой от других точек останова.
Также можно отметить выбранную группу точек останова как группу по умолчанию, гарантируя, что все вновь добавленные точки останова будут автоматически включаться в эту группу.
Чтобы создать группу точек останова, щелкните правой кнопкой мыши на любую точку останова в окне Breakpoints и выберите Add to Group > New Group (Добавить в группу > Новая группа). Вы можете назвать группу и добавить описание, если хотите. Добавлять точки останова в группу можно простым перетаскиванием или через контекстное меню.
Чтобы установить группу точек останова в качестве группы по умолчанию, просто щелкните правой кнопкой мыши по группе и выберите Set as Default Group (Установить как группу по умолчанию). Группа по умолчанию будет обозначена жирным шрифтом. Если у вас есть группа точек останова по умолчанию, все новые точки останова, которые вы добавляете в код, будут автоматически добавляться в эту группу.
Вы можете получить доступ ко всем действиям группы точек останова из контекстного меню или панели инструментов в окне Breakpoints.
Источник: https://devblogs.microsoft.com/visualstudio/organize-your-breakpoints-like-a-pro/
👍24
  День 2077. #BlazorBasics
Основы Blazor. Разбираем Шаблон Проекта Веб-Приложения Blazor. Начало
Решение о том, какой шаблон Blazor использовать, зависит от типа приложения, которое вы хотите создать. ASP.NET Core в .NET 8 вышел со значительными обновлениями архитектуры Blazor, которые включают новые режимы рендеринга, обеспечивающие большую производительность и гибкость.
Основы режимов рендеринга
ASP.NET Core с .NET 8 поддерживает 4 режима рендеринга.
1. Static Server
Статический SSR (Server Side Rendering) отображает статический HTML на сервере с помощью компонентов ASP.NET Razor. Как следует из названия, статический SSR не предлагает никакой интерактивности и полагается на стандартные POST-запросы веб-формы.
2. Interactive Server
Интерактивный SSR с использованием Blazor Server использует соединение SignalR для передачи событий и обновлений между сервером и веб-браузером.
3. Interactive WebAssembly
Interactive WebAssembly использует Blazor WebAssembly для рендеринга компонентов на клиенте. Логика приложения выполняется средой выполнения .NET WebAssembly.
4. Interactive Auto
Interactive Auto изначально будет выполнять рендеринг с использованием Blazor Server. Пока ресурсы для Blazor WebAssembly загружаются в браузер, приложение использует Blazor Server. После кэширования ресурсов Blazor WebAssembly последующие посещения будут работать с использованием Blazor WebAssembly.
Выбор правильного шаблона
В настоящее время существует довольно много вариантов шаблонов для Blazor. Решение о том, какой шаблон использовать, будет зависеть от типа приложения, которое вы хотите создать. Здесь мы сосредоточимся на шаблоне Blazor Web App, но сначала рассмотрим каждый вариант, чтобы понять различия (см. картинку).
- Blazor Web App — шаблон для создания приложения Blazor с серверным рендерингом и дополнительными режимами интерактивности сервера и клиента.
- Blazor Standalone WebAssembly App — используется для создания приложения Blazor WebAssembly с клиентским рендерингом и интерактивностью. Он не включает в себя серверный проект в решении. Этот шаблон идеально подходит для прогрессивных веб-приложений (PWA). Контент PWA можно добавить, отметив опцию Progressive Web Application во время настройки.
- Blazor Server App — используется для создания приложения Blazor с глобальной серверной интерактивностью. Шаблон предназначен только для запуска новых приложений .NET 6 и 7. Для приложений .NET 8 используйте шаблон Blazor Web App.
- Blazor Empty — базовая версия шаблона Server App. Предназначен только для запуска новых приложений .NET 6 и 7.
- .NET MAUI Blazor Hybrid App — используется для создания гибридного приложения Blazor и .NET MAUI. Идеально подходит для приложений, которые могут работать в Интернете, на настольных компьютерах и мобильных устройствах.
Новый шаблон Blazor Web App был создан как отправная точка для старта разработки под Blazor. В нём можно использовать несколько параметров для настройки генерируемого кода.
Продолжение следует…
Источник: https://www.telerik.com/blogs/unified-blazor-web-app-project-template-fully-explained
Основы Blazor. Разбираем Шаблон Проекта Веб-Приложения Blazor. Начало
Решение о том, какой шаблон Blazor использовать, зависит от типа приложения, которое вы хотите создать. ASP.NET Core в .NET 8 вышел со значительными обновлениями архитектуры Blazor, которые включают новые режимы рендеринга, обеспечивающие большую производительность и гибкость.
Основы режимов рендеринга
ASP.NET Core с .NET 8 поддерживает 4 режима рендеринга.
1. Static Server
Статический SSR (Server Side Rendering) отображает статический HTML на сервере с помощью компонентов ASP.NET Razor. Как следует из названия, статический SSR не предлагает никакой интерактивности и полагается на стандартные POST-запросы веб-формы.
2. Interactive Server
Интерактивный SSR с использованием Blazor Server использует соединение SignalR для передачи событий и обновлений между сервером и веб-браузером.
3. Interactive WebAssembly
Interactive WebAssembly использует Blazor WebAssembly для рендеринга компонентов на клиенте. Логика приложения выполняется средой выполнения .NET WebAssembly.
4. Interactive Auto
Interactive Auto изначально будет выполнять рендеринг с использованием Blazor Server. Пока ресурсы для Blazor WebAssembly загружаются в браузер, приложение использует Blazor Server. После кэширования ресурсов Blazor WebAssembly последующие посещения будут работать с использованием Blazor WebAssembly.
Выбор правильного шаблона
В настоящее время существует довольно много вариантов шаблонов для Blazor. Решение о том, какой шаблон использовать, будет зависеть от типа приложения, которое вы хотите создать. Здесь мы сосредоточимся на шаблоне Blazor Web App, но сначала рассмотрим каждый вариант, чтобы понять различия (см. картинку).
- Blazor Web App — шаблон для создания приложения Blazor с серверным рендерингом и дополнительными режимами интерактивности сервера и клиента.
- Blazor Standalone WebAssembly App — используется для создания приложения Blazor WebAssembly с клиентским рендерингом и интерактивностью. Он не включает в себя серверный проект в решении. Этот шаблон идеально подходит для прогрессивных веб-приложений (PWA). Контент PWA можно добавить, отметив опцию Progressive Web Application во время настройки.
- Blazor Server App — используется для создания приложения Blazor с глобальной серверной интерактивностью. Шаблон предназначен только для запуска новых приложений .NET 6 и 7. Для приложений .NET 8 используйте шаблон Blazor Web App.
- Blazor Empty — базовая версия шаблона Server App. Предназначен только для запуска новых приложений .NET 6 и 7.
- .NET MAUI Blazor Hybrid App — используется для создания гибридного приложения Blazor и .NET MAUI. Идеально подходит для приложений, которые могут работать в Интернете, на настольных компьютерах и мобильных устройствах.
Новый шаблон Blazor Web App был создан как отправная точка для старта разработки под Blazor. В нём можно использовать несколько параметров для настройки генерируемого кода.
Продолжение следует…
Источник: https://www.telerik.com/blogs/unified-blazor-web-app-project-template-fully-explained
👍21
  День 2078. #BlazorBasics
Основы Blazor. Разбираем Шаблон Проекта Веб-Приложения Blazor. Продолжение
Начало
Базовая конфигурация
Диалоговое окно Blazor Web App (см. картинку) предлагает много параметров для создания нового приложения Blazor: аутентификация, режим рендеринга, местоположение интерактивности и многое другое. Рассмотрим каждый набор параметров, чтобы понять, как это влияет на сгенерированный контент.
Базовое приложение Blazor
С этой конфигурацией приложение не будет иметь интерактивности, будет включать только файлы, необходимые для запуска приложения, и будет использовать статический рендеринг на стороне сервера.
Кроме того, мы отключим параметр Include sample pages (Включить примеры страниц) и выберем None (Нет) для Interactive render mode (Режим интерактивного рендеринга) (см. картинку).
Поскольку это «голая» конфигурация, каждый файл, включённый в это решение, будет отображаться во всех проектах, хотя иногда файлы будут включать дополнительный код для поддержки определённых функций.
Компоненты HeadOutlet и Routes являются дочерними элементами компонента App, и их параметры могут различаться в зависимости от выбранного режима рендеринга.
Запуск «голого» приложения отобразит домашнюю страницу с “Hello, world!”.
Такой вариант подходит для начала с нуля, т.к. присутствует только минимальный набор компонентов.
Добавление примеров страниц
Если создать проект с опцией «Включить примеры страниц», приложение не будет иметь интерактивности, но будет включать статические ресурсы для предоставления базовой темы, элементы навигации и образец компонента для отображения данных.
Также добавятся примеры компонента страницы (Weather) и меню (NavMenu). В компоненте Weather
Эта конфигурация является хорошим началом для приложений, которым не требуется интерактивность. Дополнительные примеры тем и компонентов полезны для быстрого начала работы. Далее рассмотрим интерактивность сервера.
Продолжение следует...
Источник: https://www.telerik.com/blogs/unified-blazor-web-app-project-template-fully-explained
Основы Blazor. Разбираем Шаблон Проекта Веб-Приложения Blazor. Продолжение
Начало
Базовая конфигурация
Диалоговое окно Blazor Web App (см. картинку) предлагает много параметров для создания нового приложения Blazor: аутентификация, режим рендеринга, местоположение интерактивности и многое другое. Рассмотрим каждый набор параметров, чтобы понять, как это влияет на сгенерированный контент.
Базовое приложение Blazor
С этой конфигурацией приложение не будет иметь интерактивности, будет включать только файлы, необходимые для запуска приложения, и будет использовать статический рендеринг на стороне сервера.
Кроме того, мы отключим параметр Include sample pages (Включить примеры страниц) и выберем None (Нет) для Interactive render mode (Режим интерактивного рендеринга) (см. картинку).
Поскольку это «голая» конфигурация, каждый файл, включённый в это решение, будет отображаться во всех проектах, хотя иногда файлы будут включать дополнительный код для поддержки определённых функций.
/wwwroot — статические ресурсы: CSS, JavaScript, JSON, изображения и HTML. Содержимое этой папки всегда доступно извне после публикации приложения./Components — папка по умолчанию для компонентов приложения. Папки в Blazor автоматически определяют пространство имён компонента, если не указано иное. /../Layout — компоненты макета страницы.  /../../MainLayout.razor — макет по умолчанию для приложения.  /../../MainLayout.razor.css — CSS для компонента MainLayout. /../Pages – компоненты страниц. Они имеют директиву маршрута и могут быть связаны с URL.  /../../Error.razor – страница ошибок по умолчанию.  /../../Home.razor – домашняя страница по умолчанию. Отображается при переходе на корневой URL приложения "/". /../_Imports.razor – для глобальных директив using для всех файлов .razor в этой папке или в дочерних. /../App.razor – первый компонент, который рендерит приложение. Содержит базовый HTML приложения: теги html, head и body, ссылки на статические ресурсы (CSS, JS, шрифты и т.п.). Компоненты HeadOutlet и Routes являются дочерними элементами компонента App, и их параметры могут различаться в зависимости от выбранного режима рендеринга.
 /../Routes.razor — маршрутизатор приложения./appsettings.json — настройки приложения./Program.cs — точка входа приложения. Здесь определяется конфигурация.Запуск «голого» приложения отобразит домашнюю страницу с “Hello, world!”.
Такой вариант подходит для начала с нуля, т.к. присутствует только минимальный набор компонентов.
Добавление примеров страниц
Если создать проект с опцией «Включить примеры страниц», приложение не будет иметь интерактивности, но будет включать статические ресурсы для предоставления базовой темы, элементы навигации и образец компонента для отображения данных.
/wwwroot будет содержать минимизированный файл CSS Bootstrap и значок. Bootstrap используется для создания базовой темы для приложения. Кроме того, в файлы app.css и component.css будут добавлены темы.Также добавятся примеры компонента страницы (Weather) и меню (NavMenu). В компоненте Weather
@attribute [StreamRendering] демонстрирует пример длительного процесса рендеринга. StreamingRendering улучшает пользовательский опыт, перерисовывая компонент по мере обработки данных на сервере.Эта конфигурация является хорошим началом для приложений, которым не требуется интерактивность. Дополнительные примеры тем и компонентов полезны для быстрого начала работы. Далее рассмотрим интерактивность сервера.
Продолжение следует...
Источник: https://www.telerik.com/blogs/unified-blazor-web-app-project-template-fully-explained
👍13
  День 2079. #BlazorBasics
Основы Blazor. Разбираем Шаблон Проекта Веб-Приложения Blazor. Продолжение
1. Основы режимов рендеринга
2. Базовая конфигурация
Параметр интерактивности Server
Существует три режима интерактивности: Server, WebAssembly и Auto. И для каждого можно выбрать место настройки интерактивности Global или Per Page/Component.
Когда интерактивность добавляется в приложение Blazor, файлы App.razor и Program.cs будут настроены с параметрами для желаемого режима интерактивности. Если включен параметр Include sample pages, примеры компонентов показывают, как пользоваться выбранным режимом.
Глобальный интерактивный сервер
Interactive render mode: Server
Interactivity location: Global
В режиме интерактивного сервера (см. картинку) Program.cs включает операторы для включения этой функции:
Настройка Global применит режим рендеринга приложения в App.razor. Экземпляры компонентов HeaderOutlet и Routes получат
Примеры компонентов Counter и Weather сгенерируются в соответствии с настройкой Global. Поскольку интерактивный режим был установлен в экземпляре компонента Routes, в примерах не нужно указывать режим рендеринга. В примере компонента Weather не будет
Эта конфигурация подходит для приложений, которые будут полностью интерактивными для всех компонентов.
Постраничный/Покомпонентный интерактивный сервер
Interactive render mode: Server
Interactivity location: Per Page/Component
Сгенерированный проект будет похож на предыдущий, но компоненты App, Counter и Weather будут немного отличаться.
При использовании параметра Per Page/Component App.razor не указывает режима рендеринга для экземпляров компонентов. Это позволяет любой странице или дочернему компоненту выбирать свой режим рендеринга. Если режим рендеринга не указан, то эти компоненты рендерятся статически (без интерактивности).
Чтобы продемонстрировать гибкость проекта Per Page/Component, образцы компонентов Counter и Weather включают соответствующие конфигурации. В код компонента Counter добавлен
Эта конфигурация подходит для приложений, которые необходимо оптимизировать с помощью статической серверной отрисовки, когда интерактивность не нужна. Для компонентов, требующих интерактивности сервера, эта функция может быть включена через атрибут
Далее рассмотрим параметры режима рендеринга WebAssembly.
Продолжение следует…
Источник: https://www.telerik.com/blogs/unified-blazor-web-app-project-template-fully-explained
Основы Blazor. Разбираем Шаблон Проекта Веб-Приложения Blazor. Продолжение
1. Основы режимов рендеринга
2. Базовая конфигурация
Параметр интерактивности Server
Существует три режима интерактивности: Server, WebAssembly и Auto. И для каждого можно выбрать место настройки интерактивности Global или Per Page/Component.
Когда интерактивность добавляется в приложение Blazor, файлы App.razor и Program.cs будут настроены с параметрами для желаемого режима интерактивности. Если включен параметр Include sample pages, примеры компонентов показывают, как пользоваться выбранным режимом.
Глобальный интерактивный сервер
Interactive render mode: Server
Interactivity location: Global
В режиме интерактивного сервера (см. картинку) Program.cs включает операторы для включения этой функции:
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
Настройка Global применит режим рендеринга приложения в App.razor. Экземпляры компонентов HeaderOutlet и Routes получат
@rendermode="@InteractiveServer", т.е. любой дочерний элемент этих компонентов будет иметь интерактивность сервера.Примеры компонентов Counter и Weather сгенерируются в соответствии с настройкой Global. Поскольку интерактивный режим был установлен в экземпляре компонента Routes, в примерах не нужно указывать режим рендеринга. В примере компонента Weather не будет
@attribute [StreamRendering], поскольку интерактивность через событие OnInitializedAsync обеспечивает аналогичный опыт.Эта конфигурация подходит для приложений, которые будут полностью интерактивными для всех компонентов.
Постраничный/Покомпонентный интерактивный сервер
Interactive render mode: Server
Interactivity location: Per Page/Component
Сгенерированный проект будет похож на предыдущий, но компоненты App, Counter и Weather будут немного отличаться.
При использовании параметра Per Page/Component App.razor не указывает режима рендеринга для экземпляров компонентов. Это позволяет любой странице или дочернему компоненту выбирать свой режим рендеринга. Если режим рендеринга не указан, то эти компоненты рендерятся статически (без интерактивности).
Чтобы продемонстрировать гибкость проекта Per Page/Component, образцы компонентов Counter и Weather включают соответствующие конфигурации. В код компонента Counter добавлен
@rendermode InteractiveServer, указывающий, что он использует режим интерактивный сервер. Компонент Weather не требует интерактивности и отображается статически. @attribute [StreamRendering] используется для отображения сообщения «загрузка» во время загрузки данных компонента Weather. После загрузки данных StreamRendering обновляет компонент для окончательной отрисовки результатов.Эта конфигурация подходит для приложений, которые необходимо оптимизировать с помощью статической серверной отрисовки, когда интерактивность не нужна. Для компонентов, требующих интерактивности сервера, эта функция может быть включена через атрибут
rendermode. Далее рассмотрим параметры режима рендеринга WebAssembly.
Продолжение следует…
Источник: https://www.telerik.com/blogs/unified-blazor-web-app-project-template-fully-explained
👍12
  