День 1009. #ProjectManagement
3 Принципа Хорошей Разработки ПО. Окончание
Начало
3. Ищите проблемы и итерируйте
По правде говоря, современное ПО настолько сложно и меняется так быстро, что никакое планирование не устранит все его недостатки. Чтобы создать хорошее ПО, вам нужно сначала создать плохое, а затем активно искать проблемы, чтобы улучшить своё решение.
Можно поговорить с реальными людьми, которым вы пытаетесь помочь, чтобы понять основную проблему, которую вы хотите решить, и не использовать решение, основанное только на предвзятых предубеждениях.
Остерегайтесь бюрократических целей, маскирующихся под формулировку проблемы. «Пользователи недовольны тем, насколько сложно найти информацию на государственных веб-сайтах», — это проблема. «В рамках плана цифрового правительства нам необходимо перестроить наши веб-сайты, чтобы они соответствовали новым стандартам дизайна», - это не проблема.
Чёткая формулировка проблемы позволяет вам экспериментально проверить жизнеспособность различных решений, которые слишком сложно определить теоретически. Разговаривать с чат-ботом может быть не проще, чем перемещаться по веб-сайту, и пользователи могут не захотеть устанавливать ещё одно приложение на свои телефоны, независимо от того, насколько оно упрощает общение с госорганами. Что касается ПО, очевидные решения часто имеют фатальные недостатки, которые не проявляются до тех пор, пока не будут использованы. Задача не в том, чтобы с первого раза создать идеальный конечный продукт, а в том, чтобы выявить эти проблемы как можно быстрее и с минимальными затратами. Это делается путём создания:
- нефункциональных прототипов для тестирования UI,
- функциональных прототипов для опробования различных функций.
Наспех созданный код прототипа может помочь быстрее получить обратную связь. Всё, что создано на этом этапе, следует рассматривать как одноразовое. Желаемый результат этого процесса - не написанный код, а получить более чёткое понимание того, что нужно создать.
Хорошо понимая правильное решение, вы можете начать работу над созданием реального продукта. Вы прекращаете исследовать новые идеи и фокусируетесь на выявлении проблем, связанных с вашей конкретной реализацией. Начните с небольшого числа тестировщиков, которые быстро обнаружат очевидные ошибки. По мере того, как проблемы решаются, вы можете открывать доступ всё большему количеству людей, которые найдут более экзотические проблемы.
Большинство людей дают обратную связь только один раз. Если вы начнёте с вывода на большую аудиторию, все найдут самые очевидные ошибки, и вам некуда будет дальше идти. Даже лучшие идеи продуктов, созданные лучшими инженерами, начинаются с серьёзных проблем. Цель состоит в том, чтобы многократно улучшать качество продукта, зачищая неровности до тех пор, пока не появится хороший продукт.
Проблемы с продуктом имеют наибольшее значение после запуска. Проблема, которая возникает только в 0,1% случаев, может не быть замечена во время тестирования. Но как только у вас будет миллион пользователей, у вас будет нерешённая проблема с тысячей недовольных людей. Вам необходимо исправить проблемы, вызванные новыми мобильными устройствами, сбоями сети или атаками на систему безопасности, прежде чем они нанесут существенный вред вашим пользователям.
В целом подход заключается в использовании этих различных контуров обратной связи для эффективного выявления проблем. Небольшие контуры позволяют быстро и легко исправить очевидные ошибки, но упускают из виду более широкие проблемы. Большие позволяют выявлять более широкие проблемы, но они медленные и дорогие. Лучше использовать оба, разрешая как можно больше с помощью небольших контуров, при этом сохраняя большие для обнаружения неожиданных ошибок. Создание ПО - это не предотвращение неудач. Это обнаружение стратегического провала как можно быстрее, чтобы получить информацию, необходимую для создания чего-то хорошего.
Источник: https://www.csc.gov.sg/articles/how-to-build-good-software
3 Принципа Хорошей Разработки ПО. Окончание
Начало
3. Ищите проблемы и итерируйте
По правде говоря, современное ПО настолько сложно и меняется так быстро, что никакое планирование не устранит все его недостатки. Чтобы создать хорошее ПО, вам нужно сначала создать плохое, а затем активно искать проблемы, чтобы улучшить своё решение.
Можно поговорить с реальными людьми, которым вы пытаетесь помочь, чтобы понять основную проблему, которую вы хотите решить, и не использовать решение, основанное только на предвзятых предубеждениях.
Остерегайтесь бюрократических целей, маскирующихся под формулировку проблемы. «Пользователи недовольны тем, насколько сложно найти информацию на государственных веб-сайтах», — это проблема. «В рамках плана цифрового правительства нам необходимо перестроить наши веб-сайты, чтобы они соответствовали новым стандартам дизайна», - это не проблема.
Чёткая формулировка проблемы позволяет вам экспериментально проверить жизнеспособность различных решений, которые слишком сложно определить теоретически. Разговаривать с чат-ботом может быть не проще, чем перемещаться по веб-сайту, и пользователи могут не захотеть устанавливать ещё одно приложение на свои телефоны, независимо от того, насколько оно упрощает общение с госорганами. Что касается ПО, очевидные решения часто имеют фатальные недостатки, которые не проявляются до тех пор, пока не будут использованы. Задача не в том, чтобы с первого раза создать идеальный конечный продукт, а в том, чтобы выявить эти проблемы как можно быстрее и с минимальными затратами. Это делается путём создания:
- нефункциональных прототипов для тестирования UI,
- функциональных прототипов для опробования различных функций.
Наспех созданный код прототипа может помочь быстрее получить обратную связь. Всё, что создано на этом этапе, следует рассматривать как одноразовое. Желаемый результат этого процесса - не написанный код, а получить более чёткое понимание того, что нужно создать.
Хорошо понимая правильное решение, вы можете начать работу над созданием реального продукта. Вы прекращаете исследовать новые идеи и фокусируетесь на выявлении проблем, связанных с вашей конкретной реализацией. Начните с небольшого числа тестировщиков, которые быстро обнаружат очевидные ошибки. По мере того, как проблемы решаются, вы можете открывать доступ всё большему количеству людей, которые найдут более экзотические проблемы.
Большинство людей дают обратную связь только один раз. Если вы начнёте с вывода на большую аудиторию, все найдут самые очевидные ошибки, и вам некуда будет дальше идти. Даже лучшие идеи продуктов, созданные лучшими инженерами, начинаются с серьёзных проблем. Цель состоит в том, чтобы многократно улучшать качество продукта, зачищая неровности до тех пор, пока не появится хороший продукт.
Проблемы с продуктом имеют наибольшее значение после запуска. Проблема, которая возникает только в 0,1% случаев, может не быть замечена во время тестирования. Но как только у вас будет миллион пользователей, у вас будет нерешённая проблема с тысячей недовольных людей. Вам необходимо исправить проблемы, вызванные новыми мобильными устройствами, сбоями сети или атаками на систему безопасности, прежде чем они нанесут существенный вред вашим пользователям.
В целом подход заключается в использовании этих различных контуров обратной связи для эффективного выявления проблем. Небольшие контуры позволяют быстро и легко исправить очевидные ошибки, но упускают из виду более широкие проблемы. Большие позволяют выявлять более широкие проблемы, но они медленные и дорогие. Лучше использовать оба, разрешая как можно больше с помощью небольших контуров, при этом сохраняя большие для обнаружения неожиданных ошибок. Создание ПО - это не предотвращение неудач. Это обнаружение стратегического провала как можно быстрее, чтобы получить информацию, необходимую для создания чего-то хорошего.
Источник: https://www.csc.gov.sg/articles/how-to-build-good-software
👍1
День 1010.
Ну что ж, время подводить итоги раздачи кружек. Всех желающих отобрал и записал в общий список в порядке появления комментариев. Для выбора победителей использовал простую случайную сортировку.
Результаты на картинке. Поздравляю победителей:
- Dmitriy Bobrovskiy (@RebelionTheGrey)
- Max Kaverin (@Kamaew)
- 𝕾𝖊𝖗𝖌𝖊𝖏 (@Xx_dexter_xX)
- Oleksandr Savchuk (@san_d0)
- Vasily Vasily (@Vasily26031988)
- Matviiv Andriy (@matviiv_a)
- Alexey Chernyaev (@FixGN)
- Georgy Levchenko (@FoxTes)
- Амир Хисматуллин (@ikeima)
Пожалуйста, отпишитесь мне в личку, куда прислать кружки.
Ну что ж, время подводить итоги раздачи кружек. Всех желающих отобрал и записал в общий список в порядке появления комментариев. Для выбора победителей использовал простую случайную сортировку.
Результаты на картинке. Поздравляю победителей:
- Dmitriy Bobrovskiy (@RebelionTheGrey)
- Max Kaverin (@Kamaew)
- 𝕾𝖊𝖗𝖌𝖊𝖏 (@Xx_dexter_xX)
- Oleksandr Savchuk (@san_d0)
- Vasily Vasily (@Vasily26031988)
- Matviiv Andriy (@matviiv_a)
- Alexey Chernyaev (@FixGN)
- Georgy Levchenko (@FoxTes)
- Амир Хисматуллин (@ikeima)
Пожалуйста, отпишитесь мне в личку, куда прислать кружки.
День 1011. #Оффтоп
Давненько вам не рекомендовал видео. Поэтому сегодня в качестве компенсации нечто эпическое. Интервью Сергея Теплякова подкасту DotNet&More:
- Про собеседования
- Какие скилы сейчас важны?
- Работа в команде
- Будущее C#
- SOLID и прочие паттерны. Надо ли оно сейчас?
и про многое другое аж 2,5 часа.
Наслаждайтесь.
https://youtu.be/W7HqDCnQTkU
Давненько вам не рекомендовал видео. Поэтому сегодня в качестве компенсации нечто эпическое. Интервью Сергея Теплякова подкасту DotNet&More:
- Про собеседования
- Какие скилы сейчас важны?
- Работа в команде
- Будущее C#
- SOLID и прочие паттерны. Надо ли оно сейчас?
и про многое другое аж 2,5 часа.
Наслаждайтесь.
https://youtu.be/W7HqDCnQTkU
День 1012. #ЗаметкиНаПолях #AsyncTips
Обработка исключений из методов async Task
Задача
Спроектировать код для успешного результата несложно, но структура кода не может считаться правильной, если в ней не обрабатываются потенциальные ошибки. К счастью, обработка исключений из методов
Решение
Исключения можно перехватывать конструкцией
Это сделано для того, чтобы в простом сценарии использовался простой код. В большинстве случаев код должен распространять исключения из вызываемых асинхронных методов. Всё, что нужно сделать, — использовать
Обработка исключений при ожидании группы задач рассматривалась тут.
Async Void
Что если имеется метод
Хорошего решения не существует. Если возможно, измените метод так, чтобы он возвращал
Существует и другой возможный способ. Когда метод
Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 2.
Обработка исключений из методов async Task
Задача
Спроектировать код для успешного результата несложно, но структура кода не может считаться правильной, если в ней не обрабатываются потенциальные ошибки. К счастью, обработка исключений из методов
async Task
реализуется прямолинейно.Решение
Исключения можно перехватывать конструкцией
try/catch
, как для синхронного кода:async Task ThrowExceptionAsync()Исключения, выданные из методов
{
await Task.Delay(TimeSpan.FromSeconds(1));
throw new InvalidOperationException("Test");
}
async Task TestAsync()
{
try {
await ThrowExceptionAsync();
}
catch (InvalidOperationException) {…}
}
async Task
, помещаются в возвращаемый объект Task
. При использовании await с задачей, в которой произошёл отказ, первое исключение этой задачи выдаётся повторно. При этом исходная трассировка стека будет правильно сохранена.Это сделано для того, чтобы в простом сценарии использовался простой код. В большинстве случаев код должен распространять исключения из вызываемых асинхронных методов. Всё, что нужно сделать, — использовать
await
с задачей, возвращённой из асинхронного метода, и это исключение будет распространяться естественным образом.Обработка исключений при ожидании группы задач рассматривалась тут.
Async Void
Что если имеется метод
async void
и требуется обработать исключения, распространённые из этого метода.Хорошего решения не существует. Если возможно, измените метод так, чтобы он возвращал
Task
вместо void
. Если вам требуется использовать метод async void
, рассмотрите возможность упаковки всего кода метода в блок try/catch
.Существует и другой возможный способ. Когда метод
async void
распространяет исключение, это исключение выдаётся в контексте SynchronizationContext
, активном на момент начала выполнения метода async void
. Если среда выполнения предоставляет SynchronizationContext
, то обычно она предоставляет механизм обработки этих высокоуровневых исключений на глобальном уровне. Например, WPF предоставляет Application.DispatcherUnhandledException
, а ASP.NET — UseExceptionHandler
.Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 2.
День 1013. #ЧтоНовенького
Новые Способы Организовать Вкладки в VS 2022
В Visual Studio 2022 появилась возможность раскрашивать вкладки по проектам, чтобы было легче ориентироваться в открытых файлах. Для этого перейдите в Tools > Options > Tabs & Windows (Инструменты > Параметры > Вкладки и Окна) и выберите Colorize tabs (Раскрасить вкладки). Есть возможность раскрашивать по проектам и скоро появится возможность раскрашивать по типам файлов.
Вертикальные вкладки
Чтобы включить эту функцию, щёлкните правой кнопкой мыши любую вкладку и выберите Set Tab Layout > Place Tabs on the Left (Расположение Вкладок > Разместить Слева).
Гибкая настройка
Также добавили параметры, чтобы выделить активную вкладку жирным шрифтом, изменить максимальную/минимальную ширину вкладки и добавить дополнительную кнопку закрытия вверху документа. Это также можно сделать в Tools > Options > Tabs & Windows (Инструменты > Параметры > Вкладки и Окна).
Источник: https://devblogs.microsoft.com/visualstudio/personalize-docs/
Новые Способы Организовать Вкладки в VS 2022
В Visual Studio 2022 появилась возможность раскрашивать вкладки по проектам, чтобы было легче ориентироваться в открытых файлах. Для этого перейдите в Tools > Options > Tabs & Windows (Инструменты > Параметры > Вкладки и Окна) и выберите Colorize tabs (Раскрасить вкладки). Есть возможность раскрашивать по проектам и скоро появится возможность раскрашивать по типам файлов.
Вертикальные вкладки
Чтобы включить эту функцию, щёлкните правой кнопкой мыши любую вкладку и выберите Set Tab Layout > Place Tabs on the Left (Расположение Вкладок > Разместить Слева).
Гибкая настройка
Также добавили параметры, чтобы выделить активную вкладку жирным шрифтом, изменить максимальную/минимальную ширину вкладки и добавить дополнительную кнопку закрытия вверху документа. Это также можно сделать в Tools > Options > Tabs & Windows (Инструменты > Параметры > Вкладки и Окна).
Источник: https://devblogs.microsoft.com/visualstudio/personalize-docs/
День 1014. #ЧтоНовенького
.NET 6
Вчера состоялся релиз .NET 6. На канале уже было (и ещё будет) много постов про новинки. Здесь будет некоторое саммари. А в 19 по Москве стартует .NET Conf 2021, посвящённая .NET 6.
Основные нововведения в .NET 6:
- Эта версия .NET с долгосрочной поддержкой (LTS) – 3 года.
- Унифицированная платформа для браузера, облака, настольных компьютеров, Интернета вещей и мобильных приложений, использующих одни и те же библиотеки .NET и возможность легко обмениваться кодом.
- Производительность значительно улучшена по всем направлениям и, в частности, для файлового ввода-вывода.
- C# 10 предлагает улучшения языка, такие как записи-структуры, новые асинхронные методы, неявные директивы using, новые возможности LINQ и коллекций. В компилятор добавлены новые генераторы кода.
- Горячая перезагрузка позволяет пропустить пересборку и перезапуск приложения. Просмотр изменений возможен во время работы приложения. Поддерживается в Visual Studio 2022 и из .NET CLI для C# и Visual Basic.
- Облачная диагностика была улучшена с помощью OpenTelemetry и
- API JSON более функциональны и имеют более высокую производительность с использованием генераторов кода для сериализатора.
- Минималистические API представлены в ASP.NET Core, чтобы упростить начало работы и повысить производительность сервисов HTTP.
- Компоненты Blazor можно динамически отрисовать из JavaScript и интегрировать в существующие приложения на основе JavaScript.
- Появилась AOT-компиляция WebAssembly для приложений Blazor WebAssembly (Wasm), а также поддержка повторного связывания времени выполнения и нативных зависимостей.
- Одностраничные приложения, созданные с помощью ASP.NET Core, теперь используют более гибкий шаблон, который можно использовать с Angular, React и другими популярными JavaScript фреймворками.
- Добавлена поддержка HTTP/3, чтобы ASP.NET Core, HttpClient и gRPC могли взаимодействовать с клиентами и серверами через HTTP/3.
- File IO теперь поддерживает символические ссылки и значительно улучшил производительность благодаря переписанному с нуля FileStream.
- Безопасность улучшена за счёт поддержки OpenSSL 3, схемы шифрования ChaCha20Poly1305 и средств глубокой защиты во время выполнения.
- Однофайловые приложения можно публиковать для Linux, macOS и Windows (ранее только для Linux).
- Тримминг IL теперь более функционален и эффективен с новыми предупреждениями и анализаторами для обеспечения правильных конечных результатов.
- Были добавлены генераторы и анализаторы кода, которые помогают создавать лучший, безопасный и производительный код.
Более подробно обо всех нововведениях и улучшениях см. в источнике ниже.
Источник: https://devblogs.microsoft.com/dotnet/announcing-net-6/
.NET 6
Вчера состоялся релиз .NET 6. На канале уже было (и ещё будет) много постов про новинки. Здесь будет некоторое саммари. А в 19 по Москве стартует .NET Conf 2021, посвящённая .NET 6.
Основные нововведения в .NET 6:
- Эта версия .NET с долгосрочной поддержкой (LTS) – 3 года.
- Унифицированная платформа для браузера, облака, настольных компьютеров, Интернета вещей и мобильных приложений, использующих одни и те же библиотеки .NET и возможность легко обмениваться кодом.
- Производительность значительно улучшена по всем направлениям и, в частности, для файлового ввода-вывода.
- C# 10 предлагает улучшения языка, такие как записи-структуры, новые асинхронные методы, неявные директивы using, новые возможности LINQ и коллекций. В компилятор добавлены новые генераторы кода.
- Горячая перезагрузка позволяет пропустить пересборку и перезапуск приложения. Просмотр изменений возможен во время работы приложения. Поддерживается в Visual Studio 2022 и из .NET CLI для C# и Visual Basic.
- Облачная диагностика была улучшена с помощью OpenTelemetry и
dotnet monitor
, которые теперь поддерживаются в производственной среде и доступны в сервисе приложений Azure.- API JSON более функциональны и имеют более высокую производительность с использованием генераторов кода для сериализатора.
- Минималистические API представлены в ASP.NET Core, чтобы упростить начало работы и повысить производительность сервисов HTTP.
- Компоненты Blazor можно динамически отрисовать из JavaScript и интегрировать в существующие приложения на основе JavaScript.
- Появилась AOT-компиляция WebAssembly для приложений Blazor WebAssembly (Wasm), а также поддержка повторного связывания времени выполнения и нативных зависимостей.
- Одностраничные приложения, созданные с помощью ASP.NET Core, теперь используют более гибкий шаблон, который можно использовать с Angular, React и другими популярными JavaScript фреймворками.
- Добавлена поддержка HTTP/3, чтобы ASP.NET Core, HttpClient и gRPC могли взаимодействовать с клиентами и серверами через HTTP/3.
- File IO теперь поддерживает символические ссылки и значительно улучшил производительность благодаря переписанному с нуля FileStream.
- Безопасность улучшена за счёт поддержки OpenSSL 3, схемы шифрования ChaCha20Poly1305 и средств глубокой защиты во время выполнения.
- Однофайловые приложения можно публиковать для Linux, macOS и Windows (ранее только для Linux).
- Тримминг IL теперь более функционален и эффективен с новыми предупреждениями и анализаторами для обеспечения правильных конечных результатов.
- Были добавлены генераторы и анализаторы кода, которые помогают создавать лучший, безопасный и производительный код.
Более подробно обо всех нововведениях и улучшениях см. в источнике ниже.
Источник: https://devblogs.microsoft.com/dotnet/announcing-net-6/
День 1015. #Карьера
Как Среднему Программисту Опережать Конкурентов
Код – это не вся моя жизнь. Я также не являюсь экспертом в структурах данных и алгоритмах. По сравнению с талантами в индустрии ПО я считаю себя средним программистом. Однако даже со средними навыками я никогда не прекращал расти. Быть средним программистом само по себе не мешает карьерному росту. Вы можете перерасти своих конкурентов, если будете готовы приложить усилия в правильном направлении.
1. Изучите домен компании
Хард скилы необходимы, чтобы быть разработчиком. Как средний программист, вы уже лучше многих. Всё, что нужно сделать, это добавить функциональные знания к своему инвентарю навыков. Интересуйтесь бизнес-целями каждого куска кода, который пишете. Знание примеров реального использования помогает писать наиболее простой код, отвечающий требованиям. Приложите максимум усилий для получения комплексных знаний о бизнес-логике.
Этого легко добиться, если вы работаете над приложением с первых дней. Если же вы присоединились к проекту по ходу, множество нюансов предметной области приходится изучать самостоятельно. База данных - лучшее место для начала (поскольку это наименее изменяющаяся часть). Следующим шагом будет понимание роли, которую данные играют в приложении и для компании. Вы будете поражены количеством бизнес-задач, которые можно эффективно решить, если вы знаете, что представляют собой функциональные сущности.
2. Постепенно укрепляйте уверенность
Уверенность в себе творит чудеса. Обучение, выполнение заданий, создание чего-то нового – всё это поможет вам укрепить веру в свои способности. Продолжайте искать возможности правильно использовать своё время.
Вам понадобится немного уверенности в себе, чтобы мотивировать вас, когда вы чувствуете себя плохо. Оно убедит вас в том, что вы можете делать всё, что вам нравится. Пет-проекты могут помочь вам отвлечься, когда работа в офисе становится слишком однообразной.
3. Будьте спасителем для других и привлекайте союзников
Помимо получения удовольствия от помощи ближнему, это даёт множество карьерных преимуществ. Во-первых, возможность узнать новое. Во-вторых, создание доверительных отношений внутри компании. Необязательно быть выдающимся программистом, чтобы быть полезным. Возможно, вы не сможете помочь всем. Но объяснение, почему вы не можете помочь лучше, чем просто отказ.
4. Предлагайте решения, а не просто озвучивайте проблемы
Ваше отношение к вызовам окажет гораздо более значительное влияние на ваш карьерный рост, чем навыки программирования. Люди ценят вовлечённость. Средний программист, преданный делу, может быть ценнее, чем отличный программист, который повсюду видит проблемы. Работая в команде, вы обязательно столкнётесь с проблемами: неэффективные рабочие процессы, коллеги, которые не выкладываются на полную, и т.п. Сосредоточьтесь на решении проблем, а не просто озвучивайте их. Однако имейте в виду, что, даже если есть разумные решения, не все проблемы можно решить в одночасье. Следовательно, разработчику нужно иметь много терпения, чтобы иметь дело с неэффективными людьми и процессами.
5. Сотрудничайте, чтобы расти быстрее
Совместная работа - отличный способ проявить себя в компании. Для этого не обязательно быть профессионалом. Если вы интроверт, то это может показаться довольно сложной задачей. Но самые конструктивные идеи обычно исходят от наименее заметных людей.
Идея в том, чтобы ваше присутствие ощущалось в вашей организации. Вы не просто пара рук, которые могут написать отличный код. Вы - инженер, который может внести свой вклад в развитие. Когда дело доходит до карьерного роста, восприятие имеет большое значение. Если люди не видят вас, значит, они вас не узнают. Станьте заметными за счёт сотрудничества.
Источник: https://betterprogramming.pub/how-to-stay-ahead-of-the-competition-as-an-average-programmer-f76853677490
Автор оригинала: Lokajit Tikayatray
Как Среднему Программисту Опережать Конкурентов
Код – это не вся моя жизнь. Я также не являюсь экспертом в структурах данных и алгоритмах. По сравнению с талантами в индустрии ПО я считаю себя средним программистом. Однако даже со средними навыками я никогда не прекращал расти. Быть средним программистом само по себе не мешает карьерному росту. Вы можете перерасти своих конкурентов, если будете готовы приложить усилия в правильном направлении.
1. Изучите домен компании
Хард скилы необходимы, чтобы быть разработчиком. Как средний программист, вы уже лучше многих. Всё, что нужно сделать, это добавить функциональные знания к своему инвентарю навыков. Интересуйтесь бизнес-целями каждого куска кода, который пишете. Знание примеров реального использования помогает писать наиболее простой код, отвечающий требованиям. Приложите максимум усилий для получения комплексных знаний о бизнес-логике.
Этого легко добиться, если вы работаете над приложением с первых дней. Если же вы присоединились к проекту по ходу, множество нюансов предметной области приходится изучать самостоятельно. База данных - лучшее место для начала (поскольку это наименее изменяющаяся часть). Следующим шагом будет понимание роли, которую данные играют в приложении и для компании. Вы будете поражены количеством бизнес-задач, которые можно эффективно решить, если вы знаете, что представляют собой функциональные сущности.
2. Постепенно укрепляйте уверенность
Уверенность в себе творит чудеса. Обучение, выполнение заданий, создание чего-то нового – всё это поможет вам укрепить веру в свои способности. Продолжайте искать возможности правильно использовать своё время.
Вам понадобится немного уверенности в себе, чтобы мотивировать вас, когда вы чувствуете себя плохо. Оно убедит вас в том, что вы можете делать всё, что вам нравится. Пет-проекты могут помочь вам отвлечься, когда работа в офисе становится слишком однообразной.
3. Будьте спасителем для других и привлекайте союзников
Помимо получения удовольствия от помощи ближнему, это даёт множество карьерных преимуществ. Во-первых, возможность узнать новое. Во-вторых, создание доверительных отношений внутри компании. Необязательно быть выдающимся программистом, чтобы быть полезным. Возможно, вы не сможете помочь всем. Но объяснение, почему вы не можете помочь лучше, чем просто отказ.
4. Предлагайте решения, а не просто озвучивайте проблемы
Ваше отношение к вызовам окажет гораздо более значительное влияние на ваш карьерный рост, чем навыки программирования. Люди ценят вовлечённость. Средний программист, преданный делу, может быть ценнее, чем отличный программист, который повсюду видит проблемы. Работая в команде, вы обязательно столкнётесь с проблемами: неэффективные рабочие процессы, коллеги, которые не выкладываются на полную, и т.п. Сосредоточьтесь на решении проблем, а не просто озвучивайте их. Однако имейте в виду, что, даже если есть разумные решения, не все проблемы можно решить в одночасье. Следовательно, разработчику нужно иметь много терпения, чтобы иметь дело с неэффективными людьми и процессами.
5. Сотрудничайте, чтобы расти быстрее
Совместная работа - отличный способ проявить себя в компании. Для этого не обязательно быть профессионалом. Если вы интроверт, то это может показаться довольно сложной задачей. Но самые конструктивные идеи обычно исходят от наименее заметных людей.
Идея в том, чтобы ваше присутствие ощущалось в вашей организации. Вы не просто пара рук, которые могут написать отличный код. Вы - инженер, который может внести свой вклад в развитие. Когда дело доходит до карьерного роста, восприятие имеет большое значение. Если люди не видят вас, значит, они вас не узнают. Станьте заметными за счёт сотрудничества.
Источник: https://betterprogramming.pub/how-to-stay-ahead-of-the-competition-as-an-average-programmer-f76853677490
Автор оригинала: Lokajit Tikayatray
День 1016. #ЗаметкиНаПолях
Основы DDD с Помощью Пиццы
Предметно-ориентированное проектирование (Domain Driven Design) не предоставляет практических способов реализации архитектуры ПО, но фокусируется на нескольких основных принципах, которые могут помочь в создании поддерживаемого ПО. Чтобы понять эти концепции, мы возьмем реальный пример пиццерии. Для начала рассмотрим несколько терминов.
Домен
Это предмет, вокруг которого построено наше приложение. Каждый компонент приложения выбран, запрограммирован и развёрнут с учетом потребностей домена. Домен в нашей пиццерии - пицца, и вокруг неё нужно строить всё. Повара, ингредиенты, меню, рекламные щиты и т.д.
Контекст
Окружение домена. В нашем случае магазин - это контекст. Всё, что требуется для удовлетворения потребностей, связанных с доменом, составляет контекст.
Модели
Строительные блоки домена. Различные части, которые объединяются для решения проблемы. В нашем случае это люди в их различных ролях, ингредиенты, пицца, мебель, машины и т.д.
Единый язык
Язык и терминология, которые используются при разговоре обо всём, что попадает в контекст.
Ограниченный контекст
Подсистема или разделение ответственности. У каждого сотрудника в магазине свой набор обязанностей. Маловероятно, что шеф-повар и кассир время от времени меняются ролями, поэтому им не нужно глубоко разбираться в работе друг друга.
Принципы DDD
1. ПО моделируется вокруг бизнес домена
Бизнес домен является основой всех архитектурных решений. Бизнес-модели и программные компоненты должны быть сопоставлены друг с другом. Независимо от того, используется ли термин разработчиком или руководителем компании, он должен означать одно и то же. Окончательная версия ПО - это отражение того, как работает бизнес.
Если владелец магазина использует термины маленькая, средняя и большая, рекомендуется, чтобы кассир использовал те же термины вместо размера пиццы в сантиметрах. Это упрощает понимание разговора для обеих сторон.
2. ПО развивается в ограниченном контексте
Ограниченный контекст описывает границы, в пределах которых подсистема должна развиваться. Подсистема не должна беспокоиться о том, как изменятся другие подсистемы, или пытаться решать их проблемы.
Доставка пиццы может развиваться без согласия поваров. Точно так же доставщик не диктует, какие ингредиенты нужно использовать на кухне.
3. Домены создаются, опираясь на мнение экспертов в предметной области
Команда разработчиков должна сначала понять требования с точки зрения бизнеса, прежде чем думать о технической стороне. Специалисты в предметной области несут ответственность за уточнение требований. Они фиксируют требования домена и разрешают любые спорные ситуации. Эксперты в предметной области не обязательно должны быть нетехническими. Это может быть любой, кто внимательно изучил предметную область и имеет опыт работы с ней.
Когда пиццерии нужен рекламный щит, владелец обращается к маркетологам и дизайнерам, а не создаёт дизайн сам.
Преимущества DDD
1. Облегчает общение – все разговоры ведутся экспертами в предметной области.
2. Повышает гибкость – возможность каждой подсистеме развиваться независимо.
3. Снижает недопонимание за счет использования единых формулировок и терминов.
4. Улучшает координацию в команде из-за сужения областей контекстов.
5. Способствует появлению более чистой архитектуры, поскольку разделение задач снижает риск раздувания программных компонентов.
DDD не следует использовать, когда:
1. Не ожидается быстрого роста системы.
2. Первоначальная стоимость должна быть низкой.
3. Время на разработку ограничено.
Источник: https://dev.to/abh1navv/understanding-domain-driven-design-with-some-pizza-4gkn
Основы DDD с Помощью Пиццы
Предметно-ориентированное проектирование (Domain Driven Design) не предоставляет практических способов реализации архитектуры ПО, но фокусируется на нескольких основных принципах, которые могут помочь в создании поддерживаемого ПО. Чтобы понять эти концепции, мы возьмем реальный пример пиццерии. Для начала рассмотрим несколько терминов.
Домен
Это предмет, вокруг которого построено наше приложение. Каждый компонент приложения выбран, запрограммирован и развёрнут с учетом потребностей домена. Домен в нашей пиццерии - пицца, и вокруг неё нужно строить всё. Повара, ингредиенты, меню, рекламные щиты и т.д.
Контекст
Окружение домена. В нашем случае магазин - это контекст. Всё, что требуется для удовлетворения потребностей, связанных с доменом, составляет контекст.
Модели
Строительные блоки домена. Различные части, которые объединяются для решения проблемы. В нашем случае это люди в их различных ролях, ингредиенты, пицца, мебель, машины и т.д.
Единый язык
Язык и терминология, которые используются при разговоре обо всём, что попадает в контекст.
Ограниченный контекст
Подсистема или разделение ответственности. У каждого сотрудника в магазине свой набор обязанностей. Маловероятно, что шеф-повар и кассир время от времени меняются ролями, поэтому им не нужно глубоко разбираться в работе друг друга.
Принципы DDD
1. ПО моделируется вокруг бизнес домена
Бизнес домен является основой всех архитектурных решений. Бизнес-модели и программные компоненты должны быть сопоставлены друг с другом. Независимо от того, используется ли термин разработчиком или руководителем компании, он должен означать одно и то же. Окончательная версия ПО - это отражение того, как работает бизнес.
Если владелец магазина использует термины маленькая, средняя и большая, рекомендуется, чтобы кассир использовал те же термины вместо размера пиццы в сантиметрах. Это упрощает понимание разговора для обеих сторон.
2. ПО развивается в ограниченном контексте
Ограниченный контекст описывает границы, в пределах которых подсистема должна развиваться. Подсистема не должна беспокоиться о том, как изменятся другие подсистемы, или пытаться решать их проблемы.
Доставка пиццы может развиваться без согласия поваров. Точно так же доставщик не диктует, какие ингредиенты нужно использовать на кухне.
3. Домены создаются, опираясь на мнение экспертов в предметной области
Команда разработчиков должна сначала понять требования с точки зрения бизнеса, прежде чем думать о технической стороне. Специалисты в предметной области несут ответственность за уточнение требований. Они фиксируют требования домена и разрешают любые спорные ситуации. Эксперты в предметной области не обязательно должны быть нетехническими. Это может быть любой, кто внимательно изучил предметную область и имеет опыт работы с ней.
Когда пиццерии нужен рекламный щит, владелец обращается к маркетологам и дизайнерам, а не создаёт дизайн сам.
Преимущества DDD
1. Облегчает общение – все разговоры ведутся экспертами в предметной области.
2. Повышает гибкость – возможность каждой подсистеме развиваться независимо.
3. Снижает недопонимание за счет использования единых формулировок и терминов.
4. Улучшает координацию в команде из-за сужения областей контекстов.
5. Способствует появлению более чистой архитектуры, поскольку разделение задач снижает риск раздувания программных компонентов.
DDD не следует использовать, когда:
1. Не ожидается быстрого роста системы.
2. Первоначальная стоимость должна быть низкой.
3. Время на разработку ограничено.
Источник: https://dev.to/abh1navv/understanding-domain-driven-design-with-some-pizza-4gkn
День 1017. #ЧтоНовенького
Изменения в Структурах в C# 10
C# 10 представляет функции для структур, которые обеспечивают лучшее соответствие структур и классов.
Конструкторы без параметров и инициализаторы полей
До C# 10 каждая структура имела неявный общедоступный конструктор без параметров, который устанавливал для полей структуры значения по умолчанию. Создание конструктора без параметров для структуры было ошибкой.
Теперь вы можете добавлять конструкторы структур без параметров. Они должны быть публичными и не могут быть частичными. Если вы его не добавите, будет предоставлен неявный конструктор без параметров, устанавливающий для всех полей значения по умолчанию.
Структуры-записи
Начиная с C# 10, записи можно определять как структуры:
Структуры и так сравниваются по значению. Структуры-записи добавляют поддержку
Также поддерживается позиционная запись:
Это упрощает преобразование кортежей в именованные типы. Изменение типов возвращаемых значений с кортежа, вроде
Чтобы создать неизменяемую структуру записи, добавьте
Теперь метод
Выражение with в структурах и анонимных типах
C# 10 поддерживает выражение with для всех структур, включая структуры-записи, а также для анонимных типов:
Источник: https://devblogs.microsoft.com/dotnet/welcome-to-csharp-10/
Изменения в Структурах в C# 10
C# 10 представляет функции для структур, которые обеспечивают лучшее соответствие структур и классов.
Конструкторы без параметров и инициализаторы полей
До C# 10 каждая структура имела неявный общедоступный конструктор без параметров, который устанавливал для полей структуры значения по умолчанию. Создание конструктора без параметров для структуры было ошибкой.
Теперь вы можете добавлять конструкторы структур без параметров. Они должны быть публичными и не могут быть частичными. Если вы его не добавите, будет предоставлен неявный конструктор без параметров, устанавливающий для всех полей значения по умолчанию.
public struct Address {Можно инициализировать поля в конструкторе без параметров, как выше, либо через инициализаторы полей или свойств:
public Address() {
City = "<unknown>";
}
public string City { get; init; }
}
public struct Address {Структуры, созданные через ключевое слово
public string City { get; init; } = "<unknown>";
}
default
или при определении массива, игнорируют явные конструкторы без параметров и всегда устанавливают для членов значения по умолчанию.Структуры-записи
Начиная с C# 10, записи можно определять как структуры:
public record struct PersonВы можете продолжить определять записи как классы либо просто по слову
{
public string FirstName { get; init; }
public string LastName { get; init; }
}
record
, либо через record class
для ясности.Структуры и так сравниваются по значению. Структуры-записи добавляют поддержку
IEquatable<T>
и оператор ==
, а также включают переопределение ToString()
.Также поддерживается позиционная запись:
public record struct Person (string FirstName, string LastName);Параметры первичного конструктора становятся публичными свойствами структуры-записи. В отличие от классов-записей, неявно созданные свойства доступны для чтения и записи.
Это упрощает преобразование кортежей в именованные типы. Изменение типов возвращаемых значений с кортежа, вроде
(string FirstName, string LastName)
, на именованный тип Person, может очистить ваш код и гарантировать согласованные имена членов.Чтобы создать неизменяемую структуру записи, добавьте
readonly
в определение структуры или отдельных свойств. Инициализаторы объектов являются частью этапа построения, на котором можно установить свойства только для чтения, поэтому следующая инициализация сработает и для readonly-структур:var person = new Person { FirstName = "Mads", LastName = "Torgersen"};Модификатор sealed для ToString() в классах-записях
Теперь метод
ToString()
может включать модификатор sealed
, который не позволит его переопределять в производных типах записей.Выражение with в структурах и анонимных типах
C# 10 поддерживает выражение with для всех структур, включая структуры-записи, а также для анонимных типов:
var person2 = person with {LastName = "Kristensen"};Выражение возвращает новый экземпляр с новым значением. Вы можете обновить любое количество полей. Поля, которые вы не установили, сохранят то же значение, что и исходный экземпляр.
Источник: https://devblogs.microsoft.com/dotnet/welcome-to-csharp-10/
Вы пользуетесь структурами?
Anonymous Poll
7%
Да, постоянно
38%
Да, но редко
38%
Знаю теоретически, на практике не доводилось
15%
Нет, мало о них знаю
2%
Другой ответ (в комментариях)
День 1018. #ProjectManagement
Почему Надо Выбирать Простую Веб-архитектуру
Координация команды разработчиков — тяжелая работа! Когда команда предлагает вам варианты, не всегда легко понять, что выбрать и почему.
Почему стоит выбрать более простой вариант?
1. Экономия. ПО требует денег на создание, улучшение и поддержку. Решения влияют на бюджет в долгосрочной перспективе. Чем сложнее веб-архитектура, тем больше нужно будет потратить в долгосрочной перспективе на запуск продукта, обеспечение безопасности и улучшения.
2. Обслуживаемость. У руководителей много различных забот и мало времени. Менее сложное ПО будет легче поддерживать в будущем, что сэкономит время и нервы.
3. Доступность. Более сложные архитектуры, такие как одностраничные приложения, могут быть менее доступны по умолчанию и требуют дополнительной работы для обеспечения доступности.
4. Производительность. Приложения, использующие сложные веб-архитектуры, зачастую дольше загружают даже относительно простые данные.
Более простой подход означает:
- Меньше уровней технологий
- Использование стабильных технологий вместо передовых
- По возможности меньше сложности
Ниже представлен план различных архитектур веб-приложений, от самых простых к более сложным.
1. Если можете, сделайте статический сайт
Содержание страниц статического сайта не меняется, пока владелец сайта не обновит его, например, опубликовав новую страницу.
Когда это хороший выбор: многим компаниям просто нужно публиковать информацию о себе в сети. Статические сайты проще всего создавать, поддерживать и размещать. Кроме того, они дешевле.
2. Если статического сайта недостаточно, сделайте серверное приложение
Здесь нужно подумать о создании приложения, базы данных и надёжном хранении пользовательской информации.
Когда это хороший выбор:
- нужна система регистрации и есть разные роли пользователей в приложении,
- нужна сложная логика или обработка данных.
3. Если требуется взаимодействие на стороне клиента, добавьте JavaScript
Веб-браузер может делать вычисления, анимацию и обрабатывать взаимодействия с пользователем. Интерактивность на стороне клиента означает отображение информации или обработку логики в самом браузере.
Когда это хороший выбор: «использование достаточного количества JS» можно рассматривать как способ добавить необходимую интерактивность, не добавляя ненужной сложности. Но нужно поставить вопрос, вводятся ли новые функции в ответ на требования пользователей и тестируются ли они на постоянной основе.
4. Если требуется сложная интерактивность на стороне клиента, может потребоваться одностраничное приложение (single-page application)
React, Angular, Vue.js или Blazor - все эти фреймворки используют JavaScript в браузере для предоставления пользователям функциональных возможностей. Для них часто требуются два набора приложений: на стороне клиента для интерактивности и на стороне сервера для доставки и хранения данных.
Когда это хороший выбор: одностраничные приложения предполагают компромиссы. Из-за нескольких уровней технологий их создание может быть более дорогостоящим и сложным в обслуживании. Часто требуется дополнительная работа, чтобы сделать приложение доступным. Безопасность может быть более сложной задачей. Одностраничные приложения могут быть правильным выбором, когда вы и ваша команда взвесили эти компромиссы и определили, что для предоставления основных функций приложения необходима интенсивная интерактивность на стороне клиента, автономность или отображение данных из публичного API.
Вот несколько вопросов, которые вы можете задать при выборе вариантов веб-архитектуры в проекте:
- Как эти варианты повлияют на доступность, пользовательский опыт и безопасность?
- Сколько разных языков программирования или наборов навыков понадобится, чтобы исправлять проблемы и развёртывать обновления?
- Есть ли пример успешного приложения на этой технологией в арсенале команды?
- Что будет, если команда сменится? Насколько легко или сложно будет нанять разработчиков, обладающих схожими навыками?
Источник: https://18f.gsa.gov/2021/04/05/why_simplicity_choosing_a_web_architecture/
Почему Надо Выбирать Простую Веб-архитектуру
Координация команды разработчиков — тяжелая работа! Когда команда предлагает вам варианты, не всегда легко понять, что выбрать и почему.
Почему стоит выбрать более простой вариант?
1. Экономия. ПО требует денег на создание, улучшение и поддержку. Решения влияют на бюджет в долгосрочной перспективе. Чем сложнее веб-архитектура, тем больше нужно будет потратить в долгосрочной перспективе на запуск продукта, обеспечение безопасности и улучшения.
2. Обслуживаемость. У руководителей много различных забот и мало времени. Менее сложное ПО будет легче поддерживать в будущем, что сэкономит время и нервы.
3. Доступность. Более сложные архитектуры, такие как одностраничные приложения, могут быть менее доступны по умолчанию и требуют дополнительной работы для обеспечения доступности.
4. Производительность. Приложения, использующие сложные веб-архитектуры, зачастую дольше загружают даже относительно простые данные.
Более простой подход означает:
- Меньше уровней технологий
- Использование стабильных технологий вместо передовых
- По возможности меньше сложности
Ниже представлен план различных архитектур веб-приложений, от самых простых к более сложным.
1. Если можете, сделайте статический сайт
Содержание страниц статического сайта не меняется, пока владелец сайта не обновит его, например, опубликовав новую страницу.
Когда это хороший выбор: многим компаниям просто нужно публиковать информацию о себе в сети. Статические сайты проще всего создавать, поддерживать и размещать. Кроме того, они дешевле.
2. Если статического сайта недостаточно, сделайте серверное приложение
Здесь нужно подумать о создании приложения, базы данных и надёжном хранении пользовательской информации.
Когда это хороший выбор:
- нужна система регистрации и есть разные роли пользователей в приложении,
- нужна сложная логика или обработка данных.
3. Если требуется взаимодействие на стороне клиента, добавьте JavaScript
Веб-браузер может делать вычисления, анимацию и обрабатывать взаимодействия с пользователем. Интерактивность на стороне клиента означает отображение информации или обработку логики в самом браузере.
Когда это хороший выбор: «использование достаточного количества JS» можно рассматривать как способ добавить необходимую интерактивность, не добавляя ненужной сложности. Но нужно поставить вопрос, вводятся ли новые функции в ответ на требования пользователей и тестируются ли они на постоянной основе.
4. Если требуется сложная интерактивность на стороне клиента, может потребоваться одностраничное приложение (single-page application)
React, Angular, Vue.js или Blazor - все эти фреймворки используют JavaScript в браузере для предоставления пользователям функциональных возможностей. Для них часто требуются два набора приложений: на стороне клиента для интерактивности и на стороне сервера для доставки и хранения данных.
Когда это хороший выбор: одностраничные приложения предполагают компромиссы. Из-за нескольких уровней технологий их создание может быть более дорогостоящим и сложным в обслуживании. Часто требуется дополнительная работа, чтобы сделать приложение доступным. Безопасность может быть более сложной задачей. Одностраничные приложения могут быть правильным выбором, когда вы и ваша команда взвесили эти компромиссы и определили, что для предоставления основных функций приложения необходима интенсивная интерактивность на стороне клиента, автономность или отображение данных из публичного API.
Вот несколько вопросов, которые вы можете задать при выборе вариантов веб-архитектуры в проекте:
- Как эти варианты повлияют на доступность, пользовательский опыт и безопасность?
- Сколько разных языков программирования или наборов навыков понадобится, чтобы исправлять проблемы и развёртывать обновления?
- Есть ли пример успешного приложения на этой технологией в арсенале команды?
- Что будет, если команда сменится? Насколько легко или сложно будет нанять разработчиков, обладающих схожими навыками?
Источник: https://18f.gsa.gov/2021/04/05/why_simplicity_choosing_a_web_architecture/
День 1019. #ЧтоНовенького
Улучшения Интерполяции Строк в C# 10
Продолжаем знакомиться с новинками в новой версии C#.
Интерполированные обработчики строк
Как известно, компилятор превращает интерполированные строки в вызов
В C# 10 добавили библиотечный шаблон, который позволяет API «брать на себя» обработку аргумента в виде интерполированной строки. Когда используется интерполированная строка, компилятор проверяет, назначена ли интерполированная строка типу, который удовлетворяет шаблону обработчика интерполированной строки. Обработчик интерполированной строки - это особый тип, который преобразует интерполированную строку в обычную строку. Он применяется в специализированных сценариях обычно по соображениям производительности.
Для примера рассмотрим
Авторы API проделали некоторую работу «под капотом» и добавили перегрузки с параметрами вида
Иногда вы хотите выполнить работу по построению строки только при определенных условиях. Примером является
Наконец, вот пример фактического изменения поведения строковой интерполяции.
Константные интерполированные строки
Если все замены в интерполированной строке являются константными строками, тогда результирующая строка также будет константой. Это позволяет использовать синтаксис интерполяции строк в большем количестве мест, например в атрибутах:
Источник: https://devblogs.microsoft.com/dotnet/welcome-to-csharp-10/
Улучшения Интерполяции Строк в C# 10
Продолжаем знакомиться с новинками в новой версии C#.
Интерполированные обработчики строк
Как известно, компилятор превращает интерполированные строки в вызов
string.Format
. Это может привести к большому количеству аллокаций: упаковке аргументов, выделению массива аргументов и, конечно же, самой результирующей строки. Кроме того, он не оставляет места для манёвра в смысле самой интерполяции.В C# 10 добавили библиотечный шаблон, который позволяет API «брать на себя» обработку аргумента в виде интерполированной строки. Когда используется интерполированная строка, компилятор проверяет, назначена ли интерполированная строка типу, который удовлетворяет шаблону обработчика интерполированной строки. Обработчик интерполированной строки - это особый тип, который преобразует интерполированную строку в обычную строку. Он применяется в специализированных сценариях обычно по соображениям производительности.
Для примера рассмотрим
StringBuilder.Append
:var sb = new StringBuilder();До сих пор это вызывало перегрузку
sb.Append($"Привет, {args[0]}, как дела?");
Append(string? value)
, передавая туда аллоцированную и вычисленную строку, и добавляло её к StringBuilder
одним блоком. Однако теперь есть новая перегрузка Append(ref StringBuilder.AppendInterpolatedStringHandler handler)
, которая имеет приоритет над предыдущей, когда в качестве аргумента используется интерполированная строка.Авторы API проделали некоторую работу «под капотом» и добавили перегрузки с параметрами вида
[Something]InterpolatedStringHandler
, чтобы обрабатывать интерполированные строки более подходящим образом для своих целей. В нашем примере с добавлением строки " Привет, "
, args[0]
и ", как дела?"
будут по отдельности добавлены к StringBuilder
, что намного эффективнее, хотя имеет тот же результат.Иногда вы хотите выполнить работу по построению строки только при определенных условиях. Примером является
Debug.Assert
:Debug.Assert(condition, $"{КакойТоСложныйМетод()}");В большинстве случаев
condition
будет true
, и второй параметр не будет использоваться. Однако все аргументы вычисляются при каждом вызове, излишне замедляя выполнение. Debug.Assert
теперь имеет перегрузку с обработчиком интерполированных строк, который гарантирует, что второй аргумент даже не вычисляется, если условие истинно.Наконец, вот пример фактического изменения поведения строковой интерполяции.
String.Create()
позволяет вам указать IFormatProvider
, используемый для форматирования заменяемых выражений:String.Create(CultureInfo.InvariantCulture, $"Ответ: {result}");Значение
result
(число или дата) будет отформатировано в соответствии с переданной культурой.Константные интерполированные строки
Если все замены в интерполированной строке являются константными строками, тогда результирующая строка также будет константой. Это позволяет использовать синтаксис интерполяции строк в большем количестве мест, например в атрибутах:
[Obsolete($"Используйте {nameof(OtherMethod)}")]Обратите внимание, что замещаемые элементы должны быть заполнены константными строками. Другие типы, такие как числовые значения или значения даты, использовать нельзя, поскольку они чувствительны к культуре и не могут быть вычислены во время компиляции.
Источник: https://devblogs.microsoft.com/dotnet/welcome-to-csharp-10/
День 1020. #ЗаметкиНаПолях #AsyncTips
Когда Использовать ValueTask. Начало
Простейший способ реализации метода, возвращающего
В следующем примере показана реализация
Окончание следует…
Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Главы 2, 11.
Когда Использовать ValueTask. Начало
ValueTask<T>
используется как возвращаемый тип в ситуациях, в которых чаще всего может быть возвращён синхронный результат, а асинхронное поведение встречается реже. Обычно следует использовать Task<T>
, а не ValueTask<T>
. Рассматривать использование ValueTask<T>
в качестве возвращаемого типа следует только после профилирования, которое показывает, что это приведёт к повышению быстродействия.Простейший способ реализации метода, возвращающего
ValueTask<T>
, основан на использовании async
и await
, как и обычный async-метод. Нередко метод, возвращающий ValueTask<T>
, способен немедленно вернуть значение. В таких случаях можно применить оптимизацию для этого сценария с использованием конструктора ValueTask<T>
, и передавать управление медленному асинхронному методу только при необходимости:public ValueTask<int> MethodAsync()Возможны ситуации, в которых требуется реализовать метод, возвращающий
{
if (CanBehaveSynchronously)
return new ValueTask<int>(13);
return new ValueTask<int>(SlowMethodAsync());
}
private Task<int> SlowMethodAsync();
ValueTask<T>
. Например, при использовании интерфейса IAsyncDisposable
, метод DisposeAsync
которого возвращает ValueTask
. В C# 8.0 и .NET Core 3.0 появилось асинхронное освобождение ресурсов. В BCL появился новый интерфейс IAsyncDisposable
, который является асинхронным аналогом IDisposable
. Также была введена команда await using
— асинхронный аналог using
. Таким образом, типы, которые собирались выполнить асинхронную работу при освобождении, получили такую возможность. Возвращаемым типом DisposeAsync
является ValueTask
, а не Task
.В следующем примере показана реализация
IAsyncDisposable
, которая выполняет свою логику асинхронного освобождения однократно. При следующих вызовах метод DisposeAsync
завершается успешно и синхронно:class MyClass : IAsyncDisposableИспользование:
{
private Func<Task> _disposeLogic;
public ValueTask DisposeAsync()
{
if (_disposeLogic == null)
return default;
// Этот простой пример непотокобезопасный;
// если сразу несколько потоков вызовут DisposeAsync,
// логика может быть выполнена более одного раза.
Func<Task> logic = _disposeLogic;
_disposeLogic = null;
return new ValueTask(logic());
}
}
await using (var myClass = new MyClass())Большинство методов должно возвращать
{
...
} // Здесь вызывается DisposeAsync (с ожиданием)
Task<T>
, поскольку при потреблении Task<T>
возникает меньше скрытых ловушек, чем при потреблении ValueTask<T>
. Чаще всего при реализации интерфейсов, использующих ValueTask
или ValueTask<T>
, можно просто применять async
и await
.Окончание следует…
Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Главы 2, 11.
День 1021. #ЗаметкиНаПолях #AsyncTips
Потребление ValueTask
Когда Использовать ValueTask
Задача
Требуется организовать потребление ValueTask<T>.
Решение
В большинстве случаев все, что необходимо сделать – добавить await:
Чтобы сделать что-то более сложное, преобразуйте ValueTask<T> в Task<T> вызовом AsTask:
Также возможны другие операции, например, асинхронное ожидание завершения нескольких операций:
Другие свойства ValueTask<T> предназначены для нетривиального использования. Обычно они работают не так, как другие известные свойства. В частности, для ValueTask<T>.Result действуют более жёсткие ограничения, чем для Task<T>.Result. Код, который синхронно получает результат от ValueTask<T>, может вызвать ValueTask<T>.Result или ValueTask<T>. GetAwaiter().GetResult(), но эти компоненты не должны вызываться до завершения ValueTask<T>. Синхронная загрузка результата из Task<T> блокирует вызывающий поток до завершения задачи; ValueTask<T> таких гарантий не даёт. Синхронное получение результатов от ValueTask или ValueTask<T> может быть выполнено только один раз, после завершения ValueTask, и это значение ValueTask уже не может использоваться для ожидания или преобразования в задачу. В противном случае вы получите непредсказуемый результат операции.
Итого
Когда ваш код вызывает метод, возвращающий ValueTask или ValueTask<T>, он должен либо немедленно выполнить await для этого ValueTask, либо немедленно вызвать AsTask для преобразования в Task. Возможно, эта простая рекомендация не исчерпывает все нетривиальные сценарии, но большинству приложений этого будет вполне достаточно.
Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 2.
Потребление ValueTask
Когда Использовать ValueTask
Задача
Требуется организовать потребление ValueTask<T>.
Решение
В большинстве случаев все, что необходимо сделать – добавить await:
ValueTask<int> MethodAsync();Также можно выполнить await после выполнения конкурентной операции, как в случае с Task<T>:
…
int value = await MethodAsync();
ValueTask<int> valueTask = MethodAsync();Однако следует помнить, что ValueTask или ValueTask<T> может ожидаться только один раз.
// Другая параллельная работа.
int value = await valueTask;
Чтобы сделать что-то более сложное, преобразуйте ValueTask<T> в Task<T> вызовом AsTask:
Task<int> task = MethodAsync().AsTask();Многократное ожидание Task<T> абсолютно безопасно.
// Другая параллельная работа.
int value = await task;
int anotherValue = await task;
Также возможны другие операции, например, асинхронное ожидание завершения нескольких операций:
Task<int> task1 = MethodAsync().AsTask();Тем не менее для каждого ValueTask<T> можно вызвать AsTask только один раз. Также вы не можете одновременно использовать await и вызвать AsTask для одного ValueTask<T>.
Task<int> task2 = MethodAsync().AsTask();
int[] results = await Task.WhenAll(task1, task2);
Другие свойства ValueTask<T> предназначены для нетривиального использования. Обычно они работают не так, как другие известные свойства. В частности, для ValueTask<T>.Result действуют более жёсткие ограничения, чем для Task<T>.Result. Код, который синхронно получает результат от ValueTask<T>, может вызвать ValueTask<T>.Result или ValueTask<T>. GetAwaiter().GetResult(), но эти компоненты не должны вызываться до завершения ValueTask<T>. Синхронная загрузка результата из Task<T> блокирует вызывающий поток до завершения задачи; ValueTask<T> таких гарантий не даёт. Синхронное получение результатов от ValueTask или ValueTask<T> может быть выполнено только один раз, после завершения ValueTask, и это значение ValueTask уже не может использоваться для ожидания или преобразования в задачу. В противном случае вы получите непредсказуемый результат операции.
Итого
Когда ваш код вызывает метод, возвращающий ValueTask или ValueTask<T>, он должен либо немедленно выполнить await для этого ValueTask, либо немедленно вызвать AsTask для преобразования в Task. Возможно, эта простая рекомендация не исчерпывает все нетривиальные сценарии, но большинству приложений этого будет вполне достаточно.
Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 2.
👍3
День 1022. #ЧтоНовенького
Улучшения Лямбда-Выражений в C# 10
Последний (по крайней мере пока) пост о новинках в новой версии C#. На всякий случай вот предыдущие посты о C# 10 и .NET 6:
- Улучшения в Асинхронности
- Улучшения в LINQ 1, 2
- PriorityQueue
- Статические абстрактные члены интерфейсов
- Обобщённая математика
- IEnumerable.Chunk()
- Глобальные Директивы Using
- Неявные Директивы Using
- Изменения в Структурах
- Улучшения Интерполяции Строк
Выведение типа в лябмдах
Лямбда-выражения теперь могут иметь «естественный» тип, то есть компилятор часто может самостоятельно определить тип лямбда-выражения. До сих пор лямбда-выражение приходилось преобразовывать в тип делегата или выражения. В большинстве случаев вы использовали один из перегруженных типов делегатов Func<…> или Action<…>:
Типы возврата для лямбда-выражений
В предыдущих примерах тип возвращаемого значения лямбда-выражения был очевиден и выводился. Это не всегда так:
Теперь вы можете помещать атрибуты в лямбда-выражения так же, как для методов и локальных функций. Cписок параметров при этом также должен быть заключен в круглые скобки:
Лямбда-выражения вызываются иначе, чем методы и локальные функции, и в результате атрибуты не имеют эффекта при вызове лямбда-выражения. Однако атрибуты лямбда-выражений по-прежнему полезны для анализа кода, и они также генерируются в методах, которые компилятор генерирует для лямбда-выражений, так что их можно обнаружить с помощью рефлексии.
Источник: https://devblogs.microsoft.com/dotnet/welcome-to-csharp-10/
Улучшения Лямбда-Выражений в C# 10
Последний (по крайней мере пока) пост о новинках в новой версии C#. На всякий случай вот предыдущие посты о C# 10 и .NET 6:
- Улучшения в Асинхронности
- Улучшения в LINQ 1, 2
- PriorityQueue
- Статические абстрактные члены интерфейсов
- Обобщённая математика
- IEnumerable.Chunk()
- Глобальные Директивы Using
- Неявные Директивы Using
- Изменения в Структурах
- Улучшения Интерполяции Строк
Выведение типа в лябмдах
Лямбда-выражения теперь могут иметь «естественный» тип, то есть компилятор часто может самостоятельно определить тип лямбда-выражения. До сих пор лямбда-выражение приходилось преобразовывать в тип делегата или выражения. В большинстве случаев вы использовали один из перегруженных типов делегатов Func<…> или Action<…>:
Func<string, int> parse = (string s) => int.Parse(s);Начиная с C# 10 компилятор может вывести тип за вас. Вы можете навести курсор на переменную и убедиться, что её тип всё так же
Func<string, int>
:var parse = (string s) => int.Parse(s);Обычно компилятор будет использовать доступный делегат
Func
или Action
, если подходящий существует. В противном случае он будет синтезировать тип делегата (например, если у вас есть ref-параметры или большое количество параметров). Не все лямбды имеют естественные типы - некоторым просто не хватает информации о типах. Например, если не указывать типы параметров, компилятор не сможет решить, какой тип делегата использовать, что приведёт к ошибке компиляции:var parse = s => int.Parse(s);Вывод естественного типа лямбды означает, что она может быть присвоена более базовому типу, например,
object
или Delegate
:Delegate parse = (string s) => int.Parse(s);В деревьях выражений используется комбинация «целевой» и «естественной» типизации. Если целевым типом является
LambdaExpression
или необобщённый Expression
(базовый тип для всех деревьев выражений), а лямбда имеет естественный тип делегата D
, будет выведен тип Expression<D>
:Expression parseExpr = (string s) => int.Parse(s);Здесь для
parseExpr
будет выведен тип Expression<Func<string, int>>
.Типы возврата для лямбда-выражений
В предыдущих примерах тип возвращаемого значения лямбда-выражения был очевиден и выводился. Это не всегда так:
var choose = (bool b) => b ? 1 : "two";В C# 10 вы можете указать явный тип возвращаемого значения для лямбда-выражения прямо перед параметрами. При этом параметры должны быть заключены в круглые скобки:
// Ошибка, т.к. тип результата непонятен
var choose = object (bool b) => b ? 1 : "two";Атрибуты лямбда-выражений
// Func<bool, object>
Теперь вы можете помещать атрибуты в лямбда-выражения так же, как для методов и локальных функций. Cписок параметров при этом также должен быть заключен в круглые скобки:
Func<string, int> parse =Как и для локальных функции, к лямбдам могут применяться только атрибуты, имеющие
[Example(1)] (s) => int.Parse(s);
var choose =
[Example(2)][Example(3)] object (bool b)
=> b ? 1 : "two";
AttributeTargets.Method
.Лямбда-выражения вызываются иначе, чем методы и локальные функции, и в результате атрибуты не имеют эффекта при вызове лямбда-выражения. Однако атрибуты лямбда-выражений по-прежнему полезны для анализа кода, и они также генерируются в методах, которые компилятор генерирует для лямбда-выражений, так что их можно обнаружить с помощью рефлексии.
Источник: https://devblogs.microsoft.com/dotnet/welcome-to-csharp-10/
Какую версию языка C# вы используете в вашей основной деятельности?
Anonymous Poll
13%
Уже 10 и .NET 6
41%
9 и .NET 5
22%
8 и .NET Core 3.x
3%
7 и .NET Core 2.x
16%
7 в .NET Framework
6%
Более старую версию (другую платформу)
День 1023. #Testing
Когда Использовать Mock-объекты
В тестировании можно пускаться в разные крайности относительно создания объектов-имитаций (mock-объектов). От имитации всего на свете до полного отказа их использовать. Обычно имитировать стоит только один конкретный тип зависимостей - неуправляемые зависимости: зависимости вне процесса, взаимодействия с которыми наблюдаются извне (SMTP-сервис, шина сообщений и т.д.).
Обычно существует несколько классов на пути от пользовательского ввода до вызова неуправляемой зависимости. Например, когда
Вам нужно имитировать акт отправки email (потому что SMTP-сервис является неуправляемой зависимостью), но какой именно класс имитировать?
Нужно имитировать самый последний класс в цепочке. Это позволяет использовать максимальное количество кода и улучшить защиту теста от ошибок.
Ещё один совет - имитировать только те типы, которыми вы владеете. Впервые он был представлен Стивом Фриманом и Натом Прайсом в их книге «Growing Object-Oriented Software, Guided by Tests».
Суть в написании собственных адаптеров поверх сторонних библиотек и имитации этих адаптеров вместо библиотечных типов. Это полезно, потому что:
1. Часто у вас нет глубокого понимания того, как работает сторонний код.
2. Даже если этот код уже предоставляет удобный интерфейс, имитировать этот интерфейс рискованно, потому что вы должны быть уверены, что поведение, которое вы имитируете, соответствует тому, что на самом деле делает внешняя библиотека.
3. Адаптеры абстрагируют несущественные технические детали стороннего кода и определяют отношения с библиотекой в условиях вашего приложения.
4. Если библиотека изменится, не придётся обновлять все тесты (и производственный код), которые с ней работают. Оболочка помогает ограничить такие изменения одним местом - самой оболочкой.
Обратите внимание, что правило имитации только тех типов, которыми вы владеете, не является на 100% строгим. Главное ограничение - ваше понимание того, как работает внешняя библиотека. Если эта библиотека тривиальна (до такой степени, что её поведение становится очевидным), то прямая имитация библиотеки становится приемлемой.
Гойко Аджич уточнил правило «Имитируйте только те типы, которые принадлежат вам», на «Имитируйте только те типы, которые вы понимаете».
Источник: https://enterprisecraftsmanship.com
Автор оригинала: Vladimir Khorikov
Когда Использовать Mock-объекты
В тестировании можно пускаться в разные крайности относительно создания объектов-имитаций (mock-объектов). От имитации всего на свете до полного отказа их использовать. Обычно имитировать стоит только один конкретный тип зависимостей - неуправляемые зависимости: зависимости вне процесса, взаимодействия с которыми наблюдаются извне (SMTP-сервис, шина сообщений и т.д.).
Обычно существует несколько классов на пути от пользовательского ввода до вызова неуправляемой зависимости. Например, когда
UserController
регистрирует пользователя, ему может потребоваться отправить email с подтверждением регистрации. Для этого контроллер может использовать вспомогательный класс, который сам использует другой класс и так далее, в конце концов вызывая SMTP-сервис.Вам нужно имитировать акт отправки email (потому что SMTP-сервис является неуправляемой зависимостью), но какой именно класс имитировать?
Нужно имитировать самый последний класс в цепочке. Это позволяет использовать максимальное количество кода и улучшить защиту теста от ошибок.
Ещё один совет - имитировать только те типы, которыми вы владеете. Впервые он был представлен Стивом Фриманом и Натом Прайсом в их книге «Growing Object-Oriented Software, Guided by Tests».
Суть в написании собственных адаптеров поверх сторонних библиотек и имитации этих адаптеров вместо библиотечных типов. Это полезно, потому что:
1. Часто у вас нет глубокого понимания того, как работает сторонний код.
2. Даже если этот код уже предоставляет удобный интерфейс, имитировать этот интерфейс рискованно, потому что вы должны быть уверены, что поведение, которое вы имитируете, соответствует тому, что на самом деле делает внешняя библиотека.
3. Адаптеры абстрагируют несущественные технические детали стороннего кода и определяют отношения с библиотекой в условиях вашего приложения.
4. Если библиотека изменится, не придётся обновлять все тесты (и производственный код), которые с ней работают. Оболочка помогает ограничить такие изменения одним местом - самой оболочкой.
Обратите внимание, что правило имитации только тех типов, которыми вы владеете, не является на 100% строгим. Главное ограничение - ваше понимание того, как работает внешняя библиотека. Если эта библиотека тривиальна (до такой степени, что её поведение становится очевидным), то прямая имитация библиотеки становится приемлемой.
Гойко Аджич уточнил правило «Имитируйте только те типы, которые принадлежат вам», на «Имитируйте только те типы, которые вы понимаете».
Источник: https://enterprisecraftsmanship.com
Автор оригинала: Vladimir Khorikov
День 1024. #ЧтоНовенького
Однофайловые Приложения в .NET 6
В .NET Core 3.0 мы познакомились с концепцией публикации приложения в виде одного exe-файла. Но в этом релизе было несколько вещей, которые не понравились людям. Основными проблемами были:
- Единственный файл exe на самом деле был самораспаковывающимся zip-архивом, который распаковывался во временное место и затем запускался. Иногда это создавало проблемы с точки зрения безопасности.
- Размер файла был астрономическим (70Мб для «Hello World»), хотя надо сказать, что он включает в себя всю среду исполнения .NET Core, поэтому на целевой машине не нужно было ничего устанавливать.
Давайте посмотрим, что изменилось в .NET 6.
Создадим простейшее консольное приложение:
Если открыть папку
Самораспаковывающегося архива, больше нет
В .NET 6 практика упаковки содержимого в большой архив была изменена на один настоящий исполняемый файл, который загружается в память, а не извлекается во временные папки. Хотя, сжатие можно по-прежнему включить с помощью флага:
.NET 6 имеет возможность убирать ненужные зависимости из вашего приложения. По умолчанию, когда вы публикуете автономное приложение, вы получаете всё. Но, используя функцию тримминга, вы можете удалить из среды исполнения зависимости, которые вы на самом деле не используете.
Заметьте, что это может привести к непредвиденным последствиям, поскольку компилятор не всегда может знать, какие зависимости вы используете, а какие нет (например, если вы используете рефлексию).
Попробуем:
Источник: https://dotnetcoretutorials.com/2021/11/10/single-file-apps-in-net-6/
Однофайловые Приложения в .NET 6
В .NET Core 3.0 мы познакомились с концепцией публикации приложения в виде одного exe-файла. Но в этом релизе было несколько вещей, которые не понравились людям. Основными проблемами были:
- Единственный файл exe на самом деле был самораспаковывающимся zip-архивом, который распаковывался во временное место и затем запускался. Иногда это создавало проблемы с точки зрения безопасности.
- Размер файла был астрономическим (70Мб для «Hello World»), хотя надо сказать, что он включает в себя всю среду исполнения .NET Core, поэтому на целевой машине не нужно было ничего устанавливать.
Давайте посмотрим, что изменилось в .NET 6.
Создадим простейшее консольное приложение:
Console.WriteLine("Hello, World!");Чтобы опубликовать это как единый исполняемый файл, выполним команду в терминале:
Console.ReadLine();
dotnet publish -p:PublishSingleFile=true -r win-x64 -c Release --self-contained trueЗаметьте, что когда вы публикуете один файл, вы должны включать целевой тип ОС, так как exe поставляется специально для этой ОС.
Если открыть папку
MyProject\bin\Release\net6.0\win-x64\publish
, там будет один EXE-файл. Он довольно большой, ~60Мб, (хотя немного меньше, чем был раньше). Исполняемый файл с параметром --self-contained false
получается размером в 151Кб. Понятно, что размер – цена включения среды исполнения.Самораспаковывающегося архива, больше нет
В .NET 6 практика упаковки содержимого в большой архив была изменена на один настоящий исполняемый файл, который загружается в память, а не извлекается во временные папки. Хотя, сжатие можно по-прежнему включить с помощью флага:
-p:EnableCompressionInSingleFile=trueТримминг IL
.NET 6 имеет возможность убирать ненужные зависимости из вашего приложения. По умолчанию, когда вы публикуете автономное приложение, вы получаете всё. Но, используя функцию тримминга, вы можете удалить из среды исполнения зависимости, которые вы на самом деле не используете.
Заметьте, что это может привести к непредвиденным последствиям, поскольку компилятор не всегда может знать, какие зависимости вы используете, а какие нет (например, если вы используете рефлексию).
Попробуем:
dotnet publish -p:PublishSingleFile=true -r win-x64 -c Release --self-contained true -p:PublishTrimmed=trueУ меня получился файл размером ~10Мб. Ещё раз замечу, что это всё приложение, включая среду исполнения. Неплохо!
Источник: https://dotnetcoretutorials.com/2021/11/10/single-file-apps-in-net-6/
День 1026. #ВопросыНаСобеседовании
Сегодня порекомендую вам очередное видео от Сергея Немчинского, в котором он отвечает на популярные вопросы про собеседования.
В какой одежде приходить? Что, если вы опоздали? Сколько времени длится собеседование? Нужно ли писать код на листочке? Почему спрашивают то, что не пригодится на конкретной позиции? Почему компании не дают фидбек в случае, если вы не подошли? И про многое другое.
Честно говоря, после просмотра очень хотелось прособеседоваться у Сергея. Жаль, что он не специализируется в .NET.
https://youtu.be/YeKmEmM7I2A
Сегодня порекомендую вам очередное видео от Сергея Немчинского, в котором он отвечает на популярные вопросы про собеседования.
В какой одежде приходить? Что, если вы опоздали? Сколько времени длится собеседование? Нужно ли писать код на листочке? Почему спрашивают то, что не пригодится на конкретной позиции? Почему компании не дают фидбек в случае, если вы не подошли? И про многое другое.
Честно говоря, после просмотра очень хотелось прособеседоваться у Сергея. Жаль, что он не специализируется в .NET.
https://youtu.be/YeKmEmM7I2A