День 1478. #ЗаметкиНаПолях #DesignPatterns
Паттерн Сервис/Репозиторий
Идея паттерна заключается в том, что код верхнего уровня должен полностью игнорировать бизнес-уровень и уровень данных приложения. То есть, если вы запрашиваете заказ, ваш код должен выглядеть примерно так:
Посмотрим на метод репозитория:
Что даёт этот паттерн? Типичный ответ: вы «можете захотеть сменить СУБД». На самом деле, это крайне маловероятно. Гораздо более вероятно, что вы захотите повторно использовать репозиторий в другом месте (возможно, из другого сервиса).
Особенности использования
1. Двойной репозиторий
Чаще всего это случается при использовании Entity Framework, который сам по себе является репозиторием. Использовать EF внутри репозитория обычно бесполезно, но бывают случаи, когда это имеет смысл. Например, если вы решили переключиться с EF на Dapper, нужно взять контекст БД, который использует сервис, и заменить его репозиторием.
2. Сквозной сервис
Рассмотрим следующий код метода сервиса:
3. Утечка ответственности
Это ситуация, когда один уровень начинает брать на себя ответственность от следующего уровня. Причина в том, что вы добавляете сложность, разделяя код на слои, но тесно связываете их, так что репозиторий зависит от сервиса. Например:
Более очевидный пример:
4. Внешний доступ
Представим, что мы вызываем внешний API. Конечно, этот вызов следует рассматривать так же, как вызов базы данных (в обоих случаях используются внешние для приложения зависимости). Почему бы не создать репозиторий, который бы вызывал API и обрабатывал его ответы так же, как если бы данные извлекались из базы? Таким образом, остальная часть системы остаётся полностью независимой от источника данных, и вы сможете поменять его в любое время.
Источник: https://pmichaels.net/service-repository-pattern/
Паттерн Сервис/Репозиторий
Идея паттерна заключается в том, что код верхнего уровня должен полностью игнорировать бизнес-уровень и уровень данных приложения. То есть, если вы запрашиваете заказ, ваш код должен выглядеть примерно так:
var order = orderService.GetOrder(12);Что делает GetOrder, не важно. Это ответственность сервиса. Хотя, там может быть что-то такое (здесь и далее псевдокод):
GetSalesOrder(id) {Сервис предоставляет некоторый функционал: получает заказ из репозитория, а затем, например, отправляет уведомление.
var order = repo.GetOrder(id);
if (order.HasAlert())
notifyService.SendAlert(order.Id);
return order;
}
Посмотрим на метод репозитория:
GetSalesOrder(id) {Репозиторий выбирает данные из двух таблиц БД и возвращает результат. Это пример хорошего использования паттерна сервис/репозиторий: каждая часть стека выполняет свою функцию.
var order = DB.RunSql(
"SELECT * FROM orders WHERE id = @id",
id);
var customer = DB.RunSql(
"SELECT * FROM customers WHERE id = @CustomerId",
order.CustomerId);
return new Order(order, customer);
}
Что даёт этот паттерн? Типичный ответ: вы «можете захотеть сменить СУБД». На самом деле, это крайне маловероятно. Гораздо более вероятно, что вы захотите повторно использовать репозиторий в другом месте (возможно, из другого сервиса).
Особенности использования
1. Двойной репозиторий
Чаще всего это случается при использовании Entity Framework, который сам по себе является репозиторием. Использовать EF внутри репозитория обычно бесполезно, но бывают случаи, когда это имеет смысл. Например, если вы решили переключиться с EF на Dapper, нужно взять контекст БД, который использует сервис, и заменить его репозиторием.
2. Сквозной сервис
Рассмотрим следующий код метода сервиса:
GetSalesOrder(id) {В этом случае он абсолютно ничего не делает, просто предоставляет оболочку, которую вы можете использовать. Можно сказать, что так весь код будет согласованным (контроллер > сервис > репозиторий), но это создаёт кучу лишних классов и делает код менее понятным. Очевидно, идеальная ситуация, когда сервис предоставляет дополнительную бизнес-логику.
return repo.GetOrder(id);
}
3. Утечка ответственности
Это ситуация, когда один уровень начинает брать на себя ответственность от следующего уровня. Причина в том, что вы добавляете сложность, разделяя код на слои, но тесно связываете их, так что репозиторий зависит от сервиса. Например:
GetSalesOrder(id) {Это кажется безобидным: на основе полученных данных мы должны или не должны получать дополнительные данные. Ясно, что какие данные извлекаются и как, - это ответственность репозитория, а не сервиса. Если мы рассматриваем примечания как особенность заказа, то везде, где извлекается заказ, потребуется эта логика. Т.е. вы не сможете вызвать репозиторий без сервиса. Если сервис и репозиторий связаны, зачем поддерживать два уровня абстракции?
var order = repo.GetOrder(id);
if (order.Name.StartsWith("a"))
order.Notes = repo.GetNotes(id);
…
return order;
}
Более очевидный пример:
CreateOrder(order, orderLines) {Очевидно, что транзакция принадлежит репозиторию и не имеет никакого отношения к сервису.
repo.StartTransaction();
repo.CreateOrder(order);
repo.CreateOrderLines(orderLines);
repo.CommitTransaction();
}
4. Внешний доступ
Представим, что мы вызываем внешний API. Конечно, этот вызов следует рассматривать так же, как вызов базы данных (в обоих случаях используются внешние для приложения зависимости). Почему бы не создать репозиторий, который бы вызывал API и обрабатывал его ответы так же, как если бы данные извлекались из базы? Таким образом, остальная часть системы остаётся полностью независимой от источника данных, и вы сможете поменять его в любое время.
Источник: https://pmichaels.net/service-repository-pattern/
👍9
День 1479. #ProjectManagement
Организация Разработки Безопасного ПО. Начало
Каждый год университеты, колледжи и курсы выпускают новых разработчиков, которые никогда не учились безопасному программированию или безопасности приложений. Это отсутствие понимания безопасности имеет последствия для разработки ПО на трёх уровнях: отдельный разработчик, пишущий небезопасный код, команда инженеров, слепо доверяющая зависимостям, и организация, считающая, что лучше всего внедрить собственные средства безопасности.
С самого начала нас учат программировать небезопасно. Мы спрашиваем у пользователя его имя, он его вводит, мы берем эти данные и отображаем их: «Привет, <имя>». Студента не учат проверке пользовательского ввода или кодированию информации на выходе, чтобы отключить любой потенциальный код, введённый пользователем и избежать межсайтового скриптинга (XSS).
Рекомендации по написанию безопасного кода
Начнём с жизненного цикла разработки системы. Некоторые общие действия по обеспечению безопасности, которые можно добавить в него, включают:
- Требования безопасности: меры, которые необходимо принять, чтобы приложение считалось безопасным. Создаём бессерверное приложение? Вот список требований безопасности, которые нужно добавить в ТЗ проекта, чтобы убедиться, что он достаточно безопасен для размещения в сети.
- Моделирование угроз: сеанс мозгового штурма, в котором участвуют как минимум один специалист по безопасности, владелец продукта и/или представитель бизнеса, а также член технической группы. Цель состоит в том, чтобы определить как можно больше потенциальных угроз для продукта, а затем работать над устранением тех из них, которые кажутся наиболее разрушительными или опасными. Это часто делается на этапе проектирования, но это можно сделать в любой момент позже.
- Сканирование кода: на этапе написания кода можно сканировать его с помощью статического инструмента тестирования безопасности приложений (SAST) или инструмента анализа состава программного обеспечения (SCA) или отправить приложение на сервер разработки и просканировать его с помощью инструмента DAST.
- Ранний взлом: на этапе тестирования можно нанять пентестера для тщательного автоматического и ручного тестирования всей системы.
- Защита кода в рабочей среде: на этапе выпуска можно настроить мониторинг, журналирование и оповещения.
Это только начало. Можно использовать некоторые элементы или ничего из перечисленного выше; главное найти действия и инструменты, которые работают для вас. Мы можем создать безопасный жизненный цикл разработки, добавив действия по безопасности во все процессы. Тем не менее, безопасностью надо заниматься всегда, а не только иногда или когда это удобно.
Если добавите даже один шаг по безопасности или лишнюю проверку, вы создадите более безопасное приложение. Ещё шаг – и оно ещё более безопасно. ПО — это всегда компромисс: мы не хотим тратить миллион долларов на безопасность приложения, которое заработает пару тысяч долларов. Мы хотим убедиться, что защищаем систему так, чтобы она соответствовала допустимым рискам. Проще говоря, мы должны работать с командой безопасности, чтобы точно решить, какой уровень безопасности требуется, но в целом, когда речь идет о безопасности, можно с уверенностью предположить, что «чем больше, тем лучше».
Окончание следует…
Источник: https://stackoverflow.blog/2023/02/09/three-layers-to-secure-a-software-development-organization
Организация Разработки Безопасного ПО. Начало
Каждый год университеты, колледжи и курсы выпускают новых разработчиков, которые никогда не учились безопасному программированию или безопасности приложений. Это отсутствие понимания безопасности имеет последствия для разработки ПО на трёх уровнях: отдельный разработчик, пишущий небезопасный код, команда инженеров, слепо доверяющая зависимостям, и организация, считающая, что лучше всего внедрить собственные средства безопасности.
С самого начала нас учат программировать небезопасно. Мы спрашиваем у пользователя его имя, он его вводит, мы берем эти данные и отображаем их: «Привет, <имя>». Студента не учат проверке пользовательского ввода или кодированию информации на выходе, чтобы отключить любой потенциальный код, введённый пользователем и избежать межсайтового скриптинга (XSS).
Рекомендации по написанию безопасного кода
Начнём с жизненного цикла разработки системы. Некоторые общие действия по обеспечению безопасности, которые можно добавить в него, включают:
- Требования безопасности: меры, которые необходимо принять, чтобы приложение считалось безопасным. Создаём бессерверное приложение? Вот список требований безопасности, которые нужно добавить в ТЗ проекта, чтобы убедиться, что он достаточно безопасен для размещения в сети.
- Моделирование угроз: сеанс мозгового штурма, в котором участвуют как минимум один специалист по безопасности, владелец продукта и/или представитель бизнеса, а также член технической группы. Цель состоит в том, чтобы определить как можно больше потенциальных угроз для продукта, а затем работать над устранением тех из них, которые кажутся наиболее разрушительными или опасными. Это часто делается на этапе проектирования, но это можно сделать в любой момент позже.
- Сканирование кода: на этапе написания кода можно сканировать его с помощью статического инструмента тестирования безопасности приложений (SAST) или инструмента анализа состава программного обеспечения (SCA) или отправить приложение на сервер разработки и просканировать его с помощью инструмента DAST.
- Ранний взлом: на этапе тестирования можно нанять пентестера для тщательного автоматического и ручного тестирования всей системы.
- Защита кода в рабочей среде: на этапе выпуска можно настроить мониторинг, журналирование и оповещения.
Это только начало. Можно использовать некоторые элементы или ничего из перечисленного выше; главное найти действия и инструменты, которые работают для вас. Мы можем создать безопасный жизненный цикл разработки, добавив действия по безопасности во все процессы. Тем не менее, безопасностью надо заниматься всегда, а не только иногда или когда это удобно.
Если добавите даже один шаг по безопасности или лишнюю проверку, вы создадите более безопасное приложение. Ещё шаг – и оно ещё более безопасно. ПО — это всегда компромисс: мы не хотим тратить миллион долларов на безопасность приложения, которое заработает пару тысяч долларов. Мы хотим убедиться, что защищаем систему так, чтобы она соответствовала допустимым рискам. Проще говоря, мы должны работать с командой безопасности, чтобы точно решить, какой уровень безопасности требуется, но в целом, когда речь идет о безопасности, можно с уверенностью предположить, что «чем больше, тем лучше».
Окончание следует…
Источник: https://stackoverflow.blog/2023/02/09/three-layers-to-secure-a-software-development-organization
👍3
День 1480. #ProjectManagement
Организация Разработки Безопасного ПО. Окончание
Начало
Нулевое доверие
Часто при разработке систем мы создаём «подразумеваемое доверие» - одна или несколько частей системы не проверяют то, что должны или могли бы проверять. Когда кто-то входит в систему, элемент управления безопасностью проверяет личность пользователя (через комбинацию имени и пароля), а затем предоставляет ему доступ к частям, к которым ему разрешён доступ. Если мы пропустим этот шаг, мы создадим подразумеваемое доверие.
Нулевое доверие означает отсутствие подразумеваемого доверия. Каждая часть системы заблокирована и открывается только в случае необходимости. Это означает закрытие всех портов, кроме тех, которые нужны, блокировку всех подключений, кроме нужных, постоянную проверку разрешений перед использованием. Не доверяйте ничему, даже другим системам, которые у вас есть как зависимости.
Примеры нулевого доверия:
- Проверка, очистка и экранирование всех входных данных (в указанном порядке)
- Каждый API, бессерверное приложение, контейнер или сервис рассматривается как отдельный остров. Они не должны доверять друг другу!
- Аутентификация и авторизация для всех! Каждая интеграция, даже с системами, созданными и поддерживаемыми вашей командой, требует аутентификации и авторизации для каждого подключения.
- Кодировка вывода. Не доверяйте вводу пользователя или вводу, который мог быть подделан!
Все возможные варианты нулевого доверия никогда не реализовываются, это нормально. Достаточно применить принципы нулевого доверия к как можно большему количеству систем.
Покупайте, заимствуйте, затем создавайте
Создать систему безопасности сложно. Они сложны по своей природе, тестируются чаще и более агрессивно, чем любая другая функция. Создание собственной системы безопасности дорогостояще, трудоёмко и потенциально опасно. Поэтому рекомендуется следующий порядок.
1. Купить
Т.к. ПО доступно немедленно, его не нужно создавать и поддерживать самостоятельно, и, скорее всего, оно было тщательнее протестировано. Хотя цена может показаться высокой, если подсчитать риск, время ожидания и долгосрочную стоимость обслуживания, почти всегда дешевле купить, чем создавать.
2. Заимствовать
Под заимствованием понимается использование открытого кода или другого кода, который вы можете использовать бесплатно, но который писали не вы. Это ПО с открытым кодом, онлайн-примеры, код от других команд, функции фреймворка и т.п. Преимущества аналогичны покупке: код доступен сразу, он бесплатный, не нужно его поддерживать самостоятельно. Однако такой код, возможно, не тестировался на безопасность, т.е. вы должны убедиться, что он безопасен, прежде чем использовать его, если это вообще возможно.
3. Создать
Если ни один из вариантов не подходит, создаём.
Это экономит деньги и время компании и снижает риски, несмотря на то что создание ПО с нуля обычно намного веселее. По возможности используйте функции безопасности, имеющиеся в вашей среде, такие как шифрование, аутентификацию и управление сеансами. Они испытаны, проверены и работают правильно! Используйте сторонние компоненты (библиотеки, пакеты и т.д.), так как они (обычно) достаточно тщательно протестированы. Проверяйте сторонний код и компоненты с помощью инструментов анализа ПО. Не пишите собственные функции безопасности, если в этом нет крайней необходимости.
Создавая безопасный жизненный цикл разработки системы, избегая подразумеваемого доверия внутри систем, которые мы создаём, и создавая собственные средства безопасности только тогда, когда это абсолютно необходимо, мы последовательно снижаем риски для компании.
Источник: https://stackoverflow.blog/2023/02/09/three-layers-to-secure-a-software-development-organization
Организация Разработки Безопасного ПО. Окончание
Начало
Нулевое доверие
Часто при разработке систем мы создаём «подразумеваемое доверие» - одна или несколько частей системы не проверяют то, что должны или могли бы проверять. Когда кто-то входит в систему, элемент управления безопасностью проверяет личность пользователя (через комбинацию имени и пароля), а затем предоставляет ему доступ к частям, к которым ему разрешён доступ. Если мы пропустим этот шаг, мы создадим подразумеваемое доверие.
Нулевое доверие означает отсутствие подразумеваемого доверия. Каждая часть системы заблокирована и открывается только в случае необходимости. Это означает закрытие всех портов, кроме тех, которые нужны, блокировку всех подключений, кроме нужных, постоянную проверку разрешений перед использованием. Не доверяйте ничему, даже другим системам, которые у вас есть как зависимости.
Примеры нулевого доверия:
- Проверка, очистка и экранирование всех входных данных (в указанном порядке)
- Каждый API, бессерверное приложение, контейнер или сервис рассматривается как отдельный остров. Они не должны доверять друг другу!
- Аутентификация и авторизация для всех! Каждая интеграция, даже с системами, созданными и поддерживаемыми вашей командой, требует аутентификации и авторизации для каждого подключения.
- Кодировка вывода. Не доверяйте вводу пользователя или вводу, который мог быть подделан!
Все возможные варианты нулевого доверия никогда не реализовываются, это нормально. Достаточно применить принципы нулевого доверия к как можно большему количеству систем.
Покупайте, заимствуйте, затем создавайте
Создать систему безопасности сложно. Они сложны по своей природе, тестируются чаще и более агрессивно, чем любая другая функция. Создание собственной системы безопасности дорогостояще, трудоёмко и потенциально опасно. Поэтому рекомендуется следующий порядок.
1. Купить
Т.к. ПО доступно немедленно, его не нужно создавать и поддерживать самостоятельно, и, скорее всего, оно было тщательнее протестировано. Хотя цена может показаться высокой, если подсчитать риск, время ожидания и долгосрочную стоимость обслуживания, почти всегда дешевле купить, чем создавать.
2. Заимствовать
Под заимствованием понимается использование открытого кода или другого кода, который вы можете использовать бесплатно, но который писали не вы. Это ПО с открытым кодом, онлайн-примеры, код от других команд, функции фреймворка и т.п. Преимущества аналогичны покупке: код доступен сразу, он бесплатный, не нужно его поддерживать самостоятельно. Однако такой код, возможно, не тестировался на безопасность, т.е. вы должны убедиться, что он безопасен, прежде чем использовать его, если это вообще возможно.
3. Создать
Если ни один из вариантов не подходит, создаём.
Это экономит деньги и время компании и снижает риски, несмотря на то что создание ПО с нуля обычно намного веселее. По возможности используйте функции безопасности, имеющиеся в вашей среде, такие как шифрование, аутентификацию и управление сеансами. Они испытаны, проверены и работают правильно! Используйте сторонние компоненты (библиотеки, пакеты и т.д.), так как они (обычно) достаточно тщательно протестированы. Проверяйте сторонний код и компоненты с помощью инструментов анализа ПО. Не пишите собственные функции безопасности, если в этом нет крайней необходимости.
Создавая безопасный жизненный цикл разработки системы, избегая подразумеваемого доверия внутри систем, которые мы создаём, и создавая собственные средства безопасности только тогда, когда это абсолютно необходимо, мы последовательно снижаем риски для компании.
Источник: https://stackoverflow.blog/2023/02/09/three-layers-to-secure-a-software-development-organization
👍7
День 1481. #Карьера
Улучшаем Эмоциональный Интеллект. Часть 9
Эмоциональный интеллект – это способность понимать эмоции и управлять ими, бесценное качество, которое поможет стать более продуктивными и улучшить отношения с другими. Вот простые правила, которые помогут развить ваш эмоциональный интеллект.
9. Правило отказа
«Извините, мы решили вам отказать».
Эти слова задевают и причиняют боль. Хочется бросить всё и убежать. Но представьте кого-нибудь из известных вам успешных людей. Они бросят попытки после простого отказа?
Правило отказа основано на принципах эмоционального интеллекта и может помочь вам преодолеть свои страхи, получить больше того, что вы хотите, и извлечь ценные уроки из этого процесса.
Есть такая игра «Терапия отказа». Основная идея в том, что в течение 30 дней вы провоцируете других отказать вам. Так вы постепенно снижаете чувствительность к боли от отказа и укрепляете уверенность в себе. Вы будете получать сотни отказов, но на самом деле во многих случаях люди согласятся дать вам, что вы просите.
Однако есть и ещё одна интересная деталь. Можно легко превратить «нет» в «может быть» или даже «да», задав один простой вопрос: «Почему?». Если вы «убежите» от отказа, вы можете только догадываться о его причинах: вас недолюбливают, вам не доверяют, вас считают сумасшедшим, возможно, вы не так одеты или плохо выглядите. Однако, тактично поинтересовавшись у отказавшего вам, почему он не может удовлетворить вашу просьбу, вы можете обнаружить, что дело вовсе не в этом, а существуют вполне объективные причины. Более того, заставив собеседника задуматься о причинах его «нет», вы можете склонить его изменить своё мнение или предложить компромисс. «Нет» далеко не всегда означает «нет и всё!». Это может значить «не сейчас» или «не совсем так, как вы это описали».
Правило отказа простое. Оно состоит из трех частей:
1. Вы ничего не получите, если не попросите об этом, поэтому не отказывайте сами себе.
2. Если вы получили ответ «нет», спросите «почему?». Это может привести к тому, что вы получите то, что хотели, или что-то близкое к этому.
3. Помните, что отказ не определяет вас как личность. Вас определяет то, как вы реагируете на отказ.
Итак, если вы хотите преодолеть страх быть отвергнутым и получить больше желаемого, не бегите от отказов, а пользуйтесь правилом отказа. Так вы начнёте превращать «нет» в «да». Что ещё более важно, вы навсегда измените свое отношение к отказам.
Источник: https://www.inc.com/justin-bariso/how-to-increase-emotional-intelligence.html
Улучшаем Эмоциональный Интеллект. Часть 9
Эмоциональный интеллект – это способность понимать эмоции и управлять ими, бесценное качество, которое поможет стать более продуктивными и улучшить отношения с другими. Вот простые правила, которые помогут развить ваш эмоциональный интеллект.
9. Правило отказа
«Извините, мы решили вам отказать».
Эти слова задевают и причиняют боль. Хочется бросить всё и убежать. Но представьте кого-нибудь из известных вам успешных людей. Они бросят попытки после простого отказа?
Правило отказа основано на принципах эмоционального интеллекта и может помочь вам преодолеть свои страхи, получить больше того, что вы хотите, и извлечь ценные уроки из этого процесса.
Есть такая игра «Терапия отказа». Основная идея в том, что в течение 30 дней вы провоцируете других отказать вам. Так вы постепенно снижаете чувствительность к боли от отказа и укрепляете уверенность в себе. Вы будете получать сотни отказов, но на самом деле во многих случаях люди согласятся дать вам, что вы просите.
Однако есть и ещё одна интересная деталь. Можно легко превратить «нет» в «может быть» или даже «да», задав один простой вопрос: «Почему?». Если вы «убежите» от отказа, вы можете только догадываться о его причинах: вас недолюбливают, вам не доверяют, вас считают сумасшедшим, возможно, вы не так одеты или плохо выглядите. Однако, тактично поинтересовавшись у отказавшего вам, почему он не может удовлетворить вашу просьбу, вы можете обнаружить, что дело вовсе не в этом, а существуют вполне объективные причины. Более того, заставив собеседника задуматься о причинах его «нет», вы можете склонить его изменить своё мнение или предложить компромисс. «Нет» далеко не всегда означает «нет и всё!». Это может значить «не сейчас» или «не совсем так, как вы это описали».
Правило отказа простое. Оно состоит из трех частей:
1. Вы ничего не получите, если не попросите об этом, поэтому не отказывайте сами себе.
2. Если вы получили ответ «нет», спросите «почему?». Это может привести к тому, что вы получите то, что хотели, или что-то близкое к этому.
3. Помните, что отказ не определяет вас как личность. Вас определяет то, как вы реагируете на отказ.
Итак, если вы хотите преодолеть страх быть отвергнутым и получить больше желаемого, не бегите от отказов, а пользуйтесь правилом отказа. Так вы начнёте превращать «нет» в «да». Что ещё более важно, вы навсегда измените свое отношение к отказам.
Источник: https://www.inc.com/justin-bariso/how-to-increase-emotional-intelligence.html
👍9
День 1482. #Курсы
Сегодня посоветую вам несколько отдельных вебинаров, как недавно прошедших, так и предстоящих, и вообще несколько сообществ, проводящих регулярные вебинары по теме .NET. Все перечисленные вебинары бесплатные.
1. Boston .NET Architecture Group
Проводят ежемесячные вебинары на тему архитектуры .NET приложений. Последний прошёл 15 февраля, тогда всем известный Стив “Ardalis” Смит рассказывал о чистой архитектуре в .NET 7. Недостатки этих вебинаров в том, что они проходят в 6 вечера по восточному времени США, т.е. глубокой ночью по нашему времени. Однако, на ютубе есть запись вебинара, которую может посмотреть любой желающий (правда, в отличие от настоящего вебинара, нельзя задавать вопросы).
Я посмотрел доклад Смита и должен сказать, что, несмотря на то, что я был знаком с чистой архитектурой, мне доклад очень понравился. Стив рассказывает о базовых принципах чистой архитектуры, разбирает, её преимущества и недостатки, меняет некоторые укоренившиеся представления об этом шаблоне (например, что он подходит только для больших проектов), рассказывает, как преобразовать имеющийся проект в чистую архитектуру, а также о своём шаблоне проекта чистой архитектуры и его особенностях.
2. JetBrains Webinars
Вебинары компании JetBrains по теме .NET.
Ближайший вебинар пройдёт 23 февраля 2023г в 18:00 по Москве.
Аарон Станнард – глава и основатель Petabridge (производителя Akka.NET, NBench и т.п.) – расскажет про трудности разработки .NET систем.
Что такое квант потока и почему он отличается в Windows Desktop и Windows Server? В чём разница между блокирующим вызовом и блокирующим потоком? Когда надо попытаться написать код без блокировки? Что означает ключевое слово volatile? Этот доклад поможет .NET разработчикам понять, почему их код работает так, как он работает, и что делать в сценариях, требующих высокой производительности. Вебинар можно посмотреть на YouTube.
3. Joberty Webinars
Сообщество разработчиков, на вебинарах которого выступают известные люди в мире .NET.
Ближайший вебинар пройдёт практически сразу по окончании предыдущего, 23 февраля 2023г в 20:00 по Москве. Милан Джованович расскажет о модульных монолитах. Почему монолитные приложения могут быть гибкими и расширяемыми? Почему не обязательно сразу начинать с микросервисов? Какие возможности даёт модульный монолит? Как их создавать и какие уроки он лично извлёк на своей практике? Регистрация на сайте.
Сегодня посоветую вам несколько отдельных вебинаров, как недавно прошедших, так и предстоящих, и вообще несколько сообществ, проводящих регулярные вебинары по теме .NET. Все перечисленные вебинары бесплатные.
1. Boston .NET Architecture Group
Проводят ежемесячные вебинары на тему архитектуры .NET приложений. Последний прошёл 15 февраля, тогда всем известный Стив “Ardalis” Смит рассказывал о чистой архитектуре в .NET 7. Недостатки этих вебинаров в том, что они проходят в 6 вечера по восточному времени США, т.е. глубокой ночью по нашему времени. Однако, на ютубе есть запись вебинара, которую может посмотреть любой желающий (правда, в отличие от настоящего вебинара, нельзя задавать вопросы).
Я посмотрел доклад Смита и должен сказать, что, несмотря на то, что я был знаком с чистой архитектурой, мне доклад очень понравился. Стив рассказывает о базовых принципах чистой архитектуры, разбирает, её преимущества и недостатки, меняет некоторые укоренившиеся представления об этом шаблоне (например, что он подходит только для больших проектов), рассказывает, как преобразовать имеющийся проект в чистую архитектуру, а также о своём шаблоне проекта чистой архитектуры и его особенностях.
2. JetBrains Webinars
Вебинары компании JetBrains по теме .NET.
Ближайший вебинар пройдёт 23 февраля 2023г в 18:00 по Москве.
Аарон Станнард – глава и основатель Petabridge (производителя Akka.NET, NBench и т.п.) – расскажет про трудности разработки .NET систем.
Что такое квант потока и почему он отличается в Windows Desktop и Windows Server? В чём разница между блокирующим вызовом и блокирующим потоком? Когда надо попытаться написать код без блокировки? Что означает ключевое слово volatile? Этот доклад поможет .NET разработчикам понять, почему их код работает так, как он работает, и что делать в сценариях, требующих высокой производительности. Вебинар можно посмотреть на YouTube.
3. Joberty Webinars
Сообщество разработчиков, на вебинарах которого выступают известные люди в мире .NET.
Ближайший вебинар пройдёт практически сразу по окончании предыдущего, 23 февраля 2023г в 20:00 по Москве. Милан Джованович расскажет о модульных монолитах. Почему монолитные приложения могут быть гибкими и расширяемыми? Почему не обязательно сразу начинать с микросервисов? Какие возможности даёт модульный монолит? Как их создавать и какие уроки он лично извлёк на своей практике? Регистрация на сайте.
👍20
День 1483. #ЗаметкиНаПолях
Обнаружение Критических Изменений Между Версиями NuGet-пакета
NuGet-пакеты можно не только добавлять в свои проекты, но и создавать самим. Не обязательно при этом размещать их публично. Они могут использоваться, например, как общие библиотеки при обмене кодом между командами.
Начиная с .NET 6, пакет SDK для .NET предоставляет новую функцию под названием Package Validation (Проверка пакетов), которая позволяет авторам NuGet-пакетов проверять несколько аспектов своих пакетов. Эта функция не включена по умолчанию, поэтому вы должны включить её, добавив свойство EnablePackageValidation в файл проекта:
При сборке пакета с помощью
Вы можете сгенерировать файл для подавления ошибок о критических изменениях, которые вы ожидаете ввести в новой версии:
Обнаружение Критических Изменений Между Версиями NuGet-пакета
NuGet-пакеты можно не только добавлять в свои проекты, но и создавать самим. Не обязательно при этом размещать их публично. Они могут использоваться, например, как общие библиотеки при обмене кодом между командами.
Начиная с .NET 6, пакет SDK для .NET предоставляет новую функцию под названием Package Validation (Проверка пакетов), которая позволяет авторам NuGet-пакетов проверять несколько аспектов своих пакетов. Эта функция не включена по умолчанию, поэтому вы должны включить её, добавив свойство EnablePackageValidation в файл проекта:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>
net6.0
</TargetFramework>
<PackageVersion>
2.0.0
</PackageVersion>
<EnablePackageValidation>
true
</EnablePackageValidation>
<PackageValidationBaselineVersion>
1.0.0
</PackageValidationBaselineVersion>
<PackageValidationBaselinePath>
path_to_nupkg\MyLibrary.1.0.0.nupkg
</PackageValidationBaselinePath>
</PropertyGroup>
</Project>
PackageValidationBaselineVersion
указывает версию пакета, которая будет использоваться в качестве базовой для проверки. Эта версия должна быть доступна в веб-канале NuGet. Если вы хотите использовать другое расположение или если базовый пакет недоступен в NuGet, вы можете вместо этого использовать свойство PackageValidationBaselinePath
.При сборке пакета с помощью
dotnet pack
SDK .NET сообщит об ошибках после сборки пакета. Например, если вы добавите к классу модификатор sealed
, .SDK сообщит об ошибке: CP0009: Type 'MyLibrary.Class1' has the sealed modifier on lib/net7.0/MyLibrary.dll but not on [Baseline] lib/net7.0/MyLibrary.dll. (Тип 'MyLibrary.Class1' имеет модификатор sealed в lib/net7.0/MyLibrary.dll, но не в базовой версии lib/net7.0/MyLibrary.dll).Вы можете сгенерировать файл для подавления ошибок о критических изменениях, которые вы ожидаете ввести в новой версии:
<PropertyGroup>Источник: https://www.meziantou.net/detecting-breaking-changes-between-two-versions-of-a-nuget-package-at-packaging.htm
<GenerateCompatibilitySuppressionFile>
true
</GenerateCompatibilitySuppressionFile>
<CompatibilitySuppressionFilePath>
ApiCompatSuppressions.xml
</CompatibilitySuppressionFilePath>
</PropertyGroup>
👍3
День 1484. #ЧтоНовенького
Улучшенный ИИ и Новые Возможности GitHub Copilot
С момента запуска GitHub Copilot идёт работа над улучшением качества и скорости отклика его предложений. Также разработан новый фильтр уязвимостей безопасности, чтобы сделать код, предлагаемый Copilot, более безопасным и помочь разработчикам выявлять небезопасные шаблоны кода во время работы.
Более мощная модель ИИ и лучшие предложения кода
Чтобы улучшить качество предложений кода, обновлена базовая модель Codex, что привело к значительному улучшению качества предложений и сокращению времени их предоставления. С момента старта в июле 2022 года общая доля принятых предложений кода Copilot выросла с 27% до 35%.
Вот основные технические усовершенствования:
- Обновлённая модель OpenAI Codex, которая обеспечивает лучшие результаты для синтеза кода.
- Лучшее понимание контекста: новая парадигма под названием Fill-In-the-Middle (FIM) предлагает разработчикам более эффективные предложения кода. Вместо того, чтобы рассматривать только предшествующий код, она также использует последующий код и заполняет промежуток. Таким образом у Copilot появляется больше контекста о вашем предполагаемом коде и о том, как он должен согласовываться с остальной частью вашей программы.
- Облегчённая модель на стороне клиента: обновлено расширение Copilot для VS Code, добавлена упрощённая модель на стороне клиента, которая улучшила общий уровень принятия предложений по коду. Для этого Copilot теперь использует базовую информацию о контексте пользователя — например, было ли принято последнее предложение — чтобы уменьшить частоту нежелательных предложений. Это привело к сокращению нежелательных предложений на 4,5%. Во второй улучшенной итерации этой модели на стороне клиента, выпущенной в январе 2023 года, заметны ещё большие улучшения в показателе принятия предложений кода.
Фильтрация уязвимостей безопасности с помощью новой системы ИИ
Запущена система предотвращения уязвимостей на основе ИИ, которая блокирует небезопасные шаблоны кодирования в режиме реального времени, чтобы сделать предложения Copilot более безопасными. Модель нацелена на наиболее распространённые уязвимые шаблоны кода, включая жёстко закодированные учетные данные, SQL-инъекции и инъекции пути.
Новая система невероятно быстра и может обнаруживать уязвимые шаблоны даже в незавершённых фрагментах кода. Это означает, что небезопасные шаблоны кодирования быстро блокируются и заменяются альтернативными предложениями.
Этот механизм - это первый важный шаг, который поможет разработчикам создавать более безопасный код с помощью GitHub Copilot.
Итого
Усовершенствованная модель ИИ, улучшенные предложения кода, улучшенная скорость отклика и повышенная безопасность — все эти улучшения теперь доступны разработчикам, использующим Copilot как для индивидуального пользования, так и для бизнеса.
Источник: https://github.blog/2023-02-14-github-copilot-now-has-a-better-ai-model-and-new-capabilities/
Улучшенный ИИ и Новые Возможности GitHub Copilot
С момента запуска GitHub Copilot идёт работа над улучшением качества и скорости отклика его предложений. Также разработан новый фильтр уязвимостей безопасности, чтобы сделать код, предлагаемый Copilot, более безопасным и помочь разработчикам выявлять небезопасные шаблоны кода во время работы.
Более мощная модель ИИ и лучшие предложения кода
Чтобы улучшить качество предложений кода, обновлена базовая модель Codex, что привело к значительному улучшению качества предложений и сокращению времени их предоставления. С момента старта в июле 2022 года общая доля принятых предложений кода Copilot выросла с 27% до 35%.
Вот основные технические усовершенствования:
- Обновлённая модель OpenAI Codex, которая обеспечивает лучшие результаты для синтеза кода.
- Лучшее понимание контекста: новая парадигма под названием Fill-In-the-Middle (FIM) предлагает разработчикам более эффективные предложения кода. Вместо того, чтобы рассматривать только предшествующий код, она также использует последующий код и заполняет промежуток. Таким образом у Copilot появляется больше контекста о вашем предполагаемом коде и о том, как он должен согласовываться с остальной частью вашей программы.
- Облегчённая модель на стороне клиента: обновлено расширение Copilot для VS Code, добавлена упрощённая модель на стороне клиента, которая улучшила общий уровень принятия предложений по коду. Для этого Copilot теперь использует базовую информацию о контексте пользователя — например, было ли принято последнее предложение — чтобы уменьшить частоту нежелательных предложений. Это привело к сокращению нежелательных предложений на 4,5%. Во второй улучшенной итерации этой модели на стороне клиента, выпущенной в январе 2023 года, заметны ещё большие улучшения в показателе принятия предложений кода.
Фильтрация уязвимостей безопасности с помощью новой системы ИИ
Запущена система предотвращения уязвимостей на основе ИИ, которая блокирует небезопасные шаблоны кодирования в режиме реального времени, чтобы сделать предложения Copilot более безопасными. Модель нацелена на наиболее распространённые уязвимые шаблоны кода, включая жёстко закодированные учетные данные, SQL-инъекции и инъекции пути.
Новая система невероятно быстра и может обнаруживать уязвимые шаблоны даже в незавершённых фрагментах кода. Это означает, что небезопасные шаблоны кодирования быстро блокируются и заменяются альтернативными предложениями.
Этот механизм - это первый важный шаг, который поможет разработчикам создавать более безопасный код с помощью GitHub Copilot.
Итого
Усовершенствованная модель ИИ, улучшенные предложения кода, улучшенная скорость отклика и повышенная безопасность — все эти улучшения теперь доступны разработчикам, использующим Copilot как для индивидуального пользования, так и для бизнеса.
Источник: https://github.blog/2023-02-14-github-copilot-now-has-a-better-ai-model-and-new-capabilities/
👍7
День 1485. #ЗаметкиНаПолях
Особенность (Производительности) JsonSerializer
System.Text.Json.JsonSerializer имеет странную особенность в отношении производительности и управления памятью. Посмотрим, что «не так» с этим кодом:
И что?
Если вы вызываете сериализацию/десериализацию нечасто, ничего страшного. Но вы можете использовать её в Entity Framework в сочетании с ValueConverter:
Источник: https://steven-giesel.com/blogPost/0e7512b0-c854-4cce-8606-765fcaf1e69c
Особенность (Производительности) JsonSerializer
System.Text.Json.JsonSerializer имеет странную особенность в отношении производительности и управления памятью. Посмотрим, что «не так» с этим кодом:
JsonSerializer.Serialize(myObject,JsonSerializerOptions используется для настройки сериализации и десериализации объектов. Он имеет несколько свойств, которые описывают, например, хотите ли вы иметь отступы в JSON. Теперь небольшой бенчмарк:
new JsonSerializerOptions(...));.
public record Test(string FirstName, string LastName);Итак, у нас 3 метода. Один без опций, второй использует статическое поле, а третий – каждый раз вызывает new(). Результаты:
[MemoryDiagnoser]
public class JsonBenchmark
{
private static readonly
JsonSerializerOptions _options = new();
public void Default()
{
for (var i = 0; i < 100; i++)
JsonSerializer.Serialize(
new Test("Steven", "Giesel"));
}
[Benchmark]
public void OptionsField()
{
for (var i = 0; i < 100; i++)
JsonSerializer.Serialize(
new Test("Steven", "Giesel"), _options);
}
[Benchmark]
public void OptionsNew()
{
for (var i = 0; i < 100; i++)
JsonSerializer.Serialize(
new Test("Steven", "Giesel"),
new JsonSerializerOptions());
}
}
| Method | Mean | Allocated |Мы видим, что создание нового экземпляра в цикле - это дорого. Очевидно, что new() требует времени и памяти. Да, но не настолько. На самом деле, если параметры не установлены, используется экземпляр по умолчанию. При передаче параметров сериализатор вызывает функцию InitializeForReflectionSerializer. Она довольно дорогая, поскольку собирает необходимую информацию о том, как выглядит ваш объект с помощью рефлексии. Если мы используем статическое поле, экземпляр инициализируется один раз, а дальше будет кэширован. При использовании new() InitializeForReflectionSerializer вызывается каждый раз.
|--------------|----------|-----------|
| Default | 13.89 us | 14.06 KB |
| OptionsField | 13.89 us | 14.06 KB |
| OptionsNew | 53.36 us | 42.79 KB |
И что?
Если вы вызываете сериализацию/десериализацию нечасто, ничего страшного. Но вы можете использовать её в Entity Framework в сочетании с ValueConverter:
protected override void OnModelCreating(ModelBuilder mb)Если у вас тысячи строк, это может быть очень дорого! Лучше взять значение по умолчанию или создать статическое поле.
{
mb
.Entity<MyModel>()
.Property(e => e.MyList)
.HasConversion(
v => JsonSerializer
.Serialize(v, new JsonSerializerOptions(…)),
v => JsonSerializer
.Deserialize<List<MyType>>(
v, new JsonSerializerOptions(…)));
}
Источник: https://steven-giesel.com/blogPost/0e7512b0-c854-4cce-8606-765fcaf1e69c
👍20
День 1486. #Testing
Ода Юнит-Тестам: в Защиту Пирамиды Тестирования. Начало
В 2014 году Дэвид Хайнемайер Ханссон взорвал мир разработки, когда на RailsConf заявил, что «TDD — это смерть». Многие последовали за ним, разделив разработчиков на два лагеря. Сегодня модульные тесты теряют своё значение в пользу интеграционных тестов, и пирамида тестирования превратилась в ромб, где главную роль теперь играют интеграционные тесты.
Каждый начинает с того, что делает всё возможное. Пробует, ошибается, пробует снова, пока кто-то не разорвёт этот круг и не предложит другой путь. Путь к набору тестов с минимальными затратами на обслуживание.
Следующие вопросы могут помочь избежать ощущения необходимости в Тестовом Ромбе вместо Пирамиды:
- Эта проблема вызвана юнит-тестами или тем, как я их пишу?
- Применяю ли я интеграционные тесты к компонентам, которые в нём нуждаются?
- Я что-то неправильно понял, что привело меня к одним и тем же утверждениям в нескольких местах?
- Улучшаю ли я свой дизайн с помощью тестов или просто тестирую существующий дизайн?
Исторически интеграционное тестирование было этапом совместного тестирования разных модулей, которые разрабатывались изолированно, часто несколькими командами. Сегодня они применяются к единицам кода, разработанным одной командой, как будто каждый файл кода является границей системы. Это стирает границы между модульными и интеграционными тестами. Это восприятие является неверным. Мы должны определить чёткие границы, которые дадут представление о роли системы и о том, как она взаимодействует с другими. Это похоже на гексагональную архитектуру (или архитектуру Порты-Адаптеры), в которой система имеет две стороны: внутреннюю и внешнюю, и нам нужно соединить эти две стороны через чётко определённые границы.
Именно такое представление проясняет связь между модульными и интеграционными тестами. Модульные тесты отвечают за проверку границы изнутри, а интеграционные - снаружи. Т.е. интеграционные тесты обеспечивают правильное поведение адаптеров, шлюзов и клиентов, которые отвечают за отношения с другими единицами разработки (API, плагины, базы данных и модули).
Поведенческое тестирование
Что означает модуль в модульных тестах? Это единица поведения. Т.е. тест не должен быть сосредоточен на одном файле, объекте или функции. Почему сложно писать модульные тесты, ориентированные на поведение?
Общая проблема со многими типами тестирования возникает из-за тесной связи между структурой ПО и тестами. Это происходит, когда разработчик упускает из виду цель тестирования и подходит к ней в чистом виде (иногда называемом белым ящиком).
Тестирование методом «белого ящика» означает тестирование с учётом внутреннего дизайна, чтобы гарантировать правильную работу системы. Это очень распространено в модульных тестах. Проблема в том, что тесты имеют тенденцию становиться слишком гранулированными, и в итоге вы получаете огромное количество тестов, которые трудно поддерживать из-за их тесной связи с базовой структурой. Частично недовольство модульными тестами связано с этим фактом. Интеграционные тесты, более удалённые от дизайна, как правило, менее подвержены влиянию рефакторинга, чем модульные.
Является ли это преимуществом интеграционных тестов или проблемой, вызванной подходом к тестированию методом белого ящика? Что, если бы мы тестировали методом чёрного ящика? Распространённым заблуждением является мнение, что тестирование чёрных ящиков можно применять только к внешним границам системы. Это не так. Наша система имеет множество границ. У каждого модуля есть свои границы, и его можно протестировать с помощью поведенческого подхода.
Окончание следует…
Источник: https://www.infoq.com/articles/unit-tests-testing-pyramid/
Ода Юнит-Тестам: в Защиту Пирамиды Тестирования. Начало
В 2014 году Дэвид Хайнемайер Ханссон взорвал мир разработки, когда на RailsConf заявил, что «TDD — это смерть». Многие последовали за ним, разделив разработчиков на два лагеря. Сегодня модульные тесты теряют своё значение в пользу интеграционных тестов, и пирамида тестирования превратилась в ромб, где главную роль теперь играют интеграционные тесты.
Каждый начинает с того, что делает всё возможное. Пробует, ошибается, пробует снова, пока кто-то не разорвёт этот круг и не предложит другой путь. Путь к набору тестов с минимальными затратами на обслуживание.
Следующие вопросы могут помочь избежать ощущения необходимости в Тестовом Ромбе вместо Пирамиды:
- Эта проблема вызвана юнит-тестами или тем, как я их пишу?
- Применяю ли я интеграционные тесты к компонентам, которые в нём нуждаются?
- Я что-то неправильно понял, что привело меня к одним и тем же утверждениям в нескольких местах?
- Улучшаю ли я свой дизайн с помощью тестов или просто тестирую существующий дизайн?
Исторически интеграционное тестирование было этапом совместного тестирования разных модулей, которые разрабатывались изолированно, часто несколькими командами. Сегодня они применяются к единицам кода, разработанным одной командой, как будто каждый файл кода является границей системы. Это стирает границы между модульными и интеграционными тестами. Это восприятие является неверным. Мы должны определить чёткие границы, которые дадут представление о роли системы и о том, как она взаимодействует с другими. Это похоже на гексагональную архитектуру (или архитектуру Порты-Адаптеры), в которой система имеет две стороны: внутреннюю и внешнюю, и нам нужно соединить эти две стороны через чётко определённые границы.
Именно такое представление проясняет связь между модульными и интеграционными тестами. Модульные тесты отвечают за проверку границы изнутри, а интеграционные - снаружи. Т.е. интеграционные тесты обеспечивают правильное поведение адаптеров, шлюзов и клиентов, которые отвечают за отношения с другими единицами разработки (API, плагины, базы данных и модули).
Поведенческое тестирование
Что означает модуль в модульных тестах? Это единица поведения. Т.е. тест не должен быть сосредоточен на одном файле, объекте или функции. Почему сложно писать модульные тесты, ориентированные на поведение?
Общая проблема со многими типами тестирования возникает из-за тесной связи между структурой ПО и тестами. Это происходит, когда разработчик упускает из виду цель тестирования и подходит к ней в чистом виде (иногда называемом белым ящиком).
Тестирование методом «белого ящика» означает тестирование с учётом внутреннего дизайна, чтобы гарантировать правильную работу системы. Это очень распространено в модульных тестах. Проблема в том, что тесты имеют тенденцию становиться слишком гранулированными, и в итоге вы получаете огромное количество тестов, которые трудно поддерживать из-за их тесной связи с базовой структурой. Частично недовольство модульными тестами связано с этим фактом. Интеграционные тесты, более удалённые от дизайна, как правило, менее подвержены влиянию рефакторинга, чем модульные.
Является ли это преимуществом интеграционных тестов или проблемой, вызванной подходом к тестированию методом белого ящика? Что, если бы мы тестировали методом чёрного ящика? Распространённым заблуждением является мнение, что тестирование чёрных ящиков можно применять только к внешним границам системы. Это не так. Наша система имеет множество границ. У каждого модуля есть свои границы, и его можно протестировать с помощью поведенческого подхода.
Окончание следует…
Источник: https://www.infoq.com/articles/unit-tests-testing-pyramid/
👍7
День 1487. #Testing
Ода Юнит-Тестам: в Защиту Пирамиды Тестирования. Окончание
Начало
Моки: всё или ничего
При подходе к тестированию методом белого ящика часто используются моки. Но когда вы злоупотребляете ими, поддерживать тесты становится сложнее. Возможно, это то, что имеет в виду Марк Симанн, когда говорит, что заглушки и моки нарушают инкапсуляцию. Как только вы начинаете сталкиваться с такой проблемой из-за тяжёлых моков, нормально начать их ненавидеть и пытаться избежать любой ценой. Подход, основанный только на тестировании API, обычно приводит к необходимости интенсивного использования моков. Так это проблема моков или неправильного их использования?
Моки и заглушки может быть сложнее поддерживать, но они существуют не просто так. У них есть важная роль в том, чтобы сделать тесты более быстрыми и стабильными. Наша обязанность контролировать их. Не стоит злоупотреблять ими сверх того, где они необходимы.
Уменьшите публичность вашего кода
Ещё один побочный эффект тестирования методом белого ящика в том, что оно приводит к раскрытию большего количества кода, чем необходимо. Валидаторы, мапперв и другие фрагменты кода, которые могут быть деталями внутренней реализации, теперь являются частью публичного контракта только потому, что мы предоставили их для тестирования. Кроме того, любой, кто работает в мире Java и C#, знает, насколько распространены интерфейсы в их кодовых базах. Опять же, ради тестов. Разработчик может ввести интерфейс, только чтобы имитировать зависимость в тестах.
Как только часть кода становится доступной извне, её становится труднее изменить, и требуются тесты. Это приводит к коду, в котором поддерживаемость является проблемой, а рефакторинг практически невозможен без переписывания тонны модульных тестов.
На первый взгляд это выглядит как аргумент в пользу интеграционных тестов, т.к. они сосредоточены на внешнем уровне, где многие из этих деталей реализации не утекают. Так проблема с модульными тестами или с их реализацией? Если мы реализуем юнит-тесты по методу чёрного ящика, игнорируя внутренние проектные решения и заботясь только о том, что нужно потребителям, это приведёт к меньшему контракту, который легче тестировать, с меньшим количеством тестов и тестами, которые легче поддерживать.
Архитектура как руководящий принцип
Тесты имеют тенденцию расти вокруг архитектуры. Мы разрабатываем системы, а затем думаем о тестировании. Когда мы это делаем, системы становится сложнее тестировать. Мы видели, как это происходит с многоуровневыми архитектурами, где зависимость от технологии доступа к данным усложняет модульное тестирование доменного уровня.
Этого можно легко избежать, приняв архитектуру с учетом изоляции тестов. От гексагональной архитектуры до чистой архитектуры — у нас есть множество вариантов. Архитектура этого типа независима от инфраструктуры. Все зависимости подключаются к системе посредством конфигурации. Это делает модульное тестирование удобным и заставляет использовать интеграционные тесты по их предназначению: тестировать адаптеры для внешнего мира.
Адаптеры для интеграционного тестирования лишь вносят слабое место в нашу стратегию тестирования. Когда вы проводите интеграционное тестирование со всеми подключёнными компонентами, вы получаете преимущество тестирования таких вещей, как конфигурация и композиция. Очевидно, мы хотим это проверить. Мы по-прежнему можем запускать тесты со всеми подключёнными компонентами. Разница в том, что они должны быть «дымовыми тестами», а не запускаться для тестирования каждого отдельного случая. Это приводит к более стабильным и надёжным тестам.
Источник: https://www.infoq.com/articles/unit-tests-testing-pyramid/
Ода Юнит-Тестам: в Защиту Пирамиды Тестирования. Окончание
Начало
Моки: всё или ничего
При подходе к тестированию методом белого ящика часто используются моки. Но когда вы злоупотребляете ими, поддерживать тесты становится сложнее. Возможно, это то, что имеет в виду Марк Симанн, когда говорит, что заглушки и моки нарушают инкапсуляцию. Как только вы начинаете сталкиваться с такой проблемой из-за тяжёлых моков, нормально начать их ненавидеть и пытаться избежать любой ценой. Подход, основанный только на тестировании API, обычно приводит к необходимости интенсивного использования моков. Так это проблема моков или неправильного их использования?
Моки и заглушки может быть сложнее поддерживать, но они существуют не просто так. У них есть важная роль в том, чтобы сделать тесты более быстрыми и стабильными. Наша обязанность контролировать их. Не стоит злоупотреблять ими сверх того, где они необходимы.
Уменьшите публичность вашего кода
Ещё один побочный эффект тестирования методом белого ящика в том, что оно приводит к раскрытию большего количества кода, чем необходимо. Валидаторы, мапперв и другие фрагменты кода, которые могут быть деталями внутренней реализации, теперь являются частью публичного контракта только потому, что мы предоставили их для тестирования. Кроме того, любой, кто работает в мире Java и C#, знает, насколько распространены интерфейсы в их кодовых базах. Опять же, ради тестов. Разработчик может ввести интерфейс, только чтобы имитировать зависимость в тестах.
Как только часть кода становится доступной извне, её становится труднее изменить, и требуются тесты. Это приводит к коду, в котором поддерживаемость является проблемой, а рефакторинг практически невозможен без переписывания тонны модульных тестов.
На первый взгляд это выглядит как аргумент в пользу интеграционных тестов, т.к. они сосредоточены на внешнем уровне, где многие из этих деталей реализации не утекают. Так проблема с модульными тестами или с их реализацией? Если мы реализуем юнит-тесты по методу чёрного ящика, игнорируя внутренние проектные решения и заботясь только о том, что нужно потребителям, это приведёт к меньшему контракту, который легче тестировать, с меньшим количеством тестов и тестами, которые легче поддерживать.
Архитектура как руководящий принцип
Тесты имеют тенденцию расти вокруг архитектуры. Мы разрабатываем системы, а затем думаем о тестировании. Когда мы это делаем, системы становится сложнее тестировать. Мы видели, как это происходит с многоуровневыми архитектурами, где зависимость от технологии доступа к данным усложняет модульное тестирование доменного уровня.
Этого можно легко избежать, приняв архитектуру с учетом изоляции тестов. От гексагональной архитектуры до чистой архитектуры — у нас есть множество вариантов. Архитектура этого типа независима от инфраструктуры. Все зависимости подключаются к системе посредством конфигурации. Это делает модульное тестирование удобным и заставляет использовать интеграционные тесты по их предназначению: тестировать адаптеры для внешнего мира.
Адаптеры для интеграционного тестирования лишь вносят слабое место в нашу стратегию тестирования. Когда вы проводите интеграционное тестирование со всеми подключёнными компонентами, вы получаете преимущество тестирования таких вещей, как конфигурация и композиция. Очевидно, мы хотим это проверить. Мы по-прежнему можем запускать тесты со всеми подключёнными компонентами. Разница в том, что они должны быть «дымовыми тестами», а не запускаться для тестирования каждого отдельного случая. Это приводит к более стабильным и надёжным тестам.
Источник: https://www.infoq.com/articles/unit-tests-testing-pyramid/
👍3
День 1488. #Карьера
Улучшаем Эмоциональный Интеллект. Часть 10
Эмоциональный интеллект – это способность понимать эмоции и управлять ими, бесценное качество, которое поможет стать более продуктивными и улучшить отношения с другими. Вот простые правила, которые помогут развить ваш эмоциональный интеллект.
10. Правило «без паники»
Паника – это «внезапный неконтролируемый страх или тревога, часто вызывающая бездумное поведение». Страх естественен и может быть полезным. Паника же мешает здравому смыслу и логическому мышлению. Она может парализовать вас или привести к решению, о котором вы потом пожалеете.
Капитан Чесли Салленбергер («Салли») 15 января 2009 г. Выполнял обычный рейс из Нью-Йорка в Шарлотт. Но всего через несколько минут полёта стая гусей столкнулась с самолетом, выведя из строя оба двигателя. Большинство людей запаниковало бы. А Салли нет. Через 208 секунд после столкновения с птицами Салленбергер благополучно посадил самолет в реку Гудзон. Все выжили, а это событие теперь известно как «Чудо на Гудзоне». Несомненно, Салленбергер и команда чувствовали страх, но не паниковали.
Тем, кто часто страдает от панических атак, может потребоваться профессиональная помощь. Но что, если вы лишь время от времени становитесь жертвой паники? Паниковали ли вы, когда:
- получали неожиданные новости,
- заблудились,
- не получали ответа на сообщение или звонок,
- теряли ключи, бумажник или что-то важное,
- сталкивались с трудной или опасной ситуацией?
Любая из этих ситуаций может быть серьезной и привести к естественному чувству страха. Но паника лишь усугубляет положение.
Вот где проявляется эмоциональный интеллект: вы должны научиться контролировать свои мысли.
Вместо того, чтобы позволить себе впасть в ступор, Салленбергер сначала практиковал самосознание: он признал свою естественную эмоциональную и физическую реакцию. Это позволило ему взяться за самоуправление: он сосредоточил мысли на том, что ему нужно сделать, чтобы спасти тех, кто находится на борту. Требовалась концентрация.
Скорее всего, вам не нужно будет принимать немедленное решение, которое будет означать жизнь или смерть для 150 человек. Но вы столкнетесь со своими сценариями «аварийной посадки». А способность демонстрировать самосознание и самоуправление может пойти вам на пользу.
Всё сводится к подготовке. Так же, как пилоты хорошо подготовлены к потенциальной катастрофе, вы можете практиковать методы, необходимые для того, чтобы держать свои эмоции под контролем:
- Правило концентрации: если вы заметили признаки паники или аврала в рабочих задачах, остановитесь.
- Правило приоритета: сосредоточьтесь на главном. Выберите два или три первоочередных дела, которые нужно сделать срочно. Затем выберите из них самое срочное, а остальные отложите.
- Правило критического мышления: не спешите. Критическое мышление требует терпения, а также способности понимать свои эмоции и удерживать их в равновесии. Не позволяйте временным эмоциям склонить вас к принятию постоянных решений, о которых вы потом пожалеете.
- Правило неловкого молчания: столкнувшись со сложным вопросом, вместо немедленного ответа сделаете паузу и глубоко подумаете о том, как вы хотите ответить. Вы можете подождать 5, 10 или даже 15 секунд, прежде чем дать ответ. Если вы не привыкли так делать, поначалу будет неловко.
Итого
В следующий раз, когда вы почувствуете волну страха, накрывающую всё тело, не паникуйте. Вместо этого найдите минутку. Признайте свои чувства. Примите ситуацию. Сосредоточьтесь на вещах, которые вы можете контролировать (вместо того, чтобы тратить время на размышления о вещах, которые вы не можете контролировать). Затем начните двигаться вперёд. Потому что именно те, кто не паникуют, спасают положение.
Источник: https://www.inc.com/justin-bariso/how-to-increase-emotional-intelligence.html
Улучшаем Эмоциональный Интеллект. Часть 10
Эмоциональный интеллект – это способность понимать эмоции и управлять ими, бесценное качество, которое поможет стать более продуктивными и улучшить отношения с другими. Вот простые правила, которые помогут развить ваш эмоциональный интеллект.
10. Правило «без паники»
Паника – это «внезапный неконтролируемый страх или тревога, часто вызывающая бездумное поведение». Страх естественен и может быть полезным. Паника же мешает здравому смыслу и логическому мышлению. Она может парализовать вас или привести к решению, о котором вы потом пожалеете.
Капитан Чесли Салленбергер («Салли») 15 января 2009 г. Выполнял обычный рейс из Нью-Йорка в Шарлотт. Но всего через несколько минут полёта стая гусей столкнулась с самолетом, выведя из строя оба двигателя. Большинство людей запаниковало бы. А Салли нет. Через 208 секунд после столкновения с птицами Салленбергер благополучно посадил самолет в реку Гудзон. Все выжили, а это событие теперь известно как «Чудо на Гудзоне». Несомненно, Салленбергер и команда чувствовали страх, но не паниковали.
Тем, кто часто страдает от панических атак, может потребоваться профессиональная помощь. Но что, если вы лишь время от времени становитесь жертвой паники? Паниковали ли вы, когда:
- получали неожиданные новости,
- заблудились,
- не получали ответа на сообщение или звонок,
- теряли ключи, бумажник или что-то важное,
- сталкивались с трудной или опасной ситуацией?
Любая из этих ситуаций может быть серьезной и привести к естественному чувству страха. Но паника лишь усугубляет положение.
Вот где проявляется эмоциональный интеллект: вы должны научиться контролировать свои мысли.
Вместо того, чтобы позволить себе впасть в ступор, Салленбергер сначала практиковал самосознание: он признал свою естественную эмоциональную и физическую реакцию. Это позволило ему взяться за самоуправление: он сосредоточил мысли на том, что ему нужно сделать, чтобы спасти тех, кто находится на борту. Требовалась концентрация.
Скорее всего, вам не нужно будет принимать немедленное решение, которое будет означать жизнь или смерть для 150 человек. Но вы столкнетесь со своими сценариями «аварийной посадки». А способность демонстрировать самосознание и самоуправление может пойти вам на пользу.
Всё сводится к подготовке. Так же, как пилоты хорошо подготовлены к потенциальной катастрофе, вы можете практиковать методы, необходимые для того, чтобы держать свои эмоции под контролем:
- Правило концентрации: если вы заметили признаки паники или аврала в рабочих задачах, остановитесь.
- Правило приоритета: сосредоточьтесь на главном. Выберите два или три первоочередных дела, которые нужно сделать срочно. Затем выберите из них самое срочное, а остальные отложите.
- Правило критического мышления: не спешите. Критическое мышление требует терпения, а также способности понимать свои эмоции и удерживать их в равновесии. Не позволяйте временным эмоциям склонить вас к принятию постоянных решений, о которых вы потом пожалеете.
- Правило неловкого молчания: столкнувшись со сложным вопросом, вместо немедленного ответа сделаете паузу и глубоко подумаете о том, как вы хотите ответить. Вы можете подождать 5, 10 или даже 15 секунд, прежде чем дать ответ. Если вы не привыкли так делать, поначалу будет неловко.
Итого
В следующий раз, когда вы почувствуете волну страха, накрывающую всё тело, не паникуйте. Вместо этого найдите минутку. Признайте свои чувства. Примите ситуацию. Сосредоточьтесь на вещах, которые вы можете контролировать (вместо того, чтобы тратить время на размышления о вещах, которые вы не можете контролировать). Затем начните двигаться вперёд. Потому что именно те, кто не паникуют, спасают положение.
Источник: https://www.inc.com/justin-bariso/how-to-increase-emotional-intelligence.html
👍9
День 1489. #ЗаметкиНаПолях
Какой Интерфейс Коллекции Использовать? Начало
В этой серии постов о том, когда использовать какой тип коллекции и почему.
Общее руководство:
- Используйте максимально общие типы для аргументов. Типы аргументов приносят наибольшую пользу, когда они максимально универсальны, потому что метод может применяться к более широкому диапазону входных значений.
- Используйте максимально конкретные типы для возвращаемых значений. Возвращаемые типы обеспечивают наибольшую пользу, когда они максимально специфичны, поскольку конкретное возвращаемое значение предоставляет больше функциональных возможностей, чем универсальное.
Использование типов коллекций (и их интерфейсов) также должно соответствовать этому правилу. Вы также должны возвращать наиболее конкретный и принимать наиболее общий тип коллекции.
Вот упрощённая иерархия интерфейсов коллекций в .NET:
- IQueryable
- IList
- Array
- IReadOnlyList
1. IQueryable — дырявая абстракция
Этот интерфейс позволяет запрашивать базу данных с помощью выражений LINQ так же, как коллекцию в памяти. Разница в том, что выражения LINQ, которые работают с IQueryable, выполняются в БД, а не в памяти. ORM, такие как EF Core и NHibernate, реализуют провайдера IQueryable, который преобразует выражения LINQ в запросы SQL. IQueryable можно рассматривать как абстракцию, позволяющую одинаково работать с разными источниками данных.
IQueryable особенно популярен в репозиториях, где вы можете ввести метод GetAll, например:
Такой подход на первый взгляд кажется логичным. Клиентский код может строить фильтры поверх IQueryable в зависимости от сценария. Но IQueryable является дырявой абстракцией, которая требует от вас знания деталей реализации, которые она должна абстрагировать. Вы должны знать, какие выражения LINQ могут быть преобразованы в SQL, а какие нет. Таким образом, использование IQueryable как части общедоступного API вводит в заблуждение. Создаётся ложное впечатление, что вы можете применить любое выражение поверх этого возвращаемого значения.
То же самое верно, когда вы принимаете выражение в качестве аргумента в репозитории, например:
Продолжение следует…
Источник: https://enterprisecraftsmanship.com/posts/which-collection-interface-to-use/
Какой Интерфейс Коллекции Использовать? Начало
В этой серии постов о том, когда использовать какой тип коллекции и почему.
Общее руководство:
- Используйте максимально общие типы для аргументов. Типы аргументов приносят наибольшую пользу, когда они максимально универсальны, потому что метод может применяться к более широкому диапазону входных значений.
- Используйте максимально конкретные типы для возвращаемых значений. Возвращаемые типы обеспечивают наибольшую пользу, когда они максимально специфичны, поскольку конкретное возвращаемое значение предоставляет больше функциональных возможностей, чем универсальное.
Использование типов коллекций (и их интерфейсов) также должно соответствовать этому правилу. Вы также должны возвращать наиболее конкретный и принимать наиболее общий тип коллекции.
Вот упрощённая иерархия интерфейсов коллекций в .NET:
IEnumerable<T>По рекомендации нужно возвращать самый конкретный тип. В этом иерархическом дереве есть несколько листьев:
└- IQueryable<T>
└- IReadOnlyCollection<T>
| └- IReadonlyList<T>
└- ICollection<T>
└- Array
└- IList<T>
- IQueryable
- IList
- Array
- IReadOnlyList
1. IQueryable — дырявая абстракция
Этот интерфейс позволяет запрашивать базу данных с помощью выражений LINQ так же, как коллекцию в памяти. Разница в том, что выражения LINQ, которые работают с IQueryable, выполняются в БД, а не в памяти. ORM, такие как EF Core и NHibernate, реализуют провайдера IQueryable, который преобразует выражения LINQ в запросы SQL. IQueryable можно рассматривать как абстракцию, позволяющую одинаково работать с разными источниками данных.
IQueryable особенно популярен в репозиториях, где вы можете ввести метод GetAll, например:
// Student repositoryА затем добавлять фильтры в клиентском коде.
public IQueryable<Student> GetAll() =>
_context.Set<Student>();
Такой подход на первый взгляд кажется логичным. Клиентский код может строить фильтры поверх IQueryable в зависимости от сценария. Но IQueryable является дырявой абстракцией, которая требует от вас знания деталей реализации, которые она должна абстрагировать. Вы должны знать, какие выражения LINQ могут быть преобразованы в SQL, а какие нет. Таким образом, использование IQueryable как части общедоступного API вводит в заблуждение. Создаётся ложное впечатление, что вы можете применить любое выражение поверх этого возвращаемого значения.
То же самое верно, когда вы принимаете выражение в качестве аргумента в репозитории, например:
public IQueryable<Student> GetAll(Решение состоит в том, чтобы не использовать IQueryable (или выражения) как часть общедоступного API репозитория. Вы можете использовать его внутри, потому что репозиторий знает, с каким ORM он работает и его ограничения. Но эти знания не должны пересекать границы репозитория, т.е. не должны утекать к клиентам репозитория.
Expression<Func<Student, bool>> predicate) =>
_context.Set<Student>().Where(predicate);
Продолжение следует…
Источник: https://enterprisecraftsmanship.com/posts/which-collection-interface-to-use/
👍22
День 1490. #ЗаметкиНаПолях
Какой Интерфейс Коллекции Использовать? Продолжение
Начало
2. IList и Array
Заметьте, что здесь говорится об интерфейсе IList, а не конкретном типе List. Они почти идентичны с точки зрения функциональности, и поэтому, хотя технически List более конкретен, чем IList, на практике не имеет большого значения, какой из них вы используете.
Например, клиентский код может изменить список студентов после того, как получит их из репозитория. Вы можете делать это по двум причинам:
- Вы изменяете коллекцию, чтобы добавить или удалить студентов из БД.
- Вы повторно используете коллекцию для других целей. Например, нужно отфильтровать студентов по некоторым критериям, и вместо создания новой коллекции вы удаляете элементы из существующей коллекции.
Обе эти причины неправильные.
Возврат изменяемой коллекции создаёт впечатление, что студентов, которых она представляет, можно изменить, просто добавив или удалив элемент из коллекции, что не так. В тот момент, когда информация о студентах покидает базу данных, эта информация отсоединяется от базы данных, и её изменение ничего не даёт.
Замечание: да, ORM (NHibernate или EF Core) позволяет эмулировать связь объектов с данными в базе, но это не наш случай, когда мы возвращаем коллекцию из метода.
Поэтому мы не должны использовать изменяемую коллекцию, поскольку она не представляет должным образом то, что клиент может и не может делать с данными в БД.
Мы также не должны модифицировать коллекцию, чтобы повторно использовать её для каких-то других целей. Если у вас нет серьёзных ограничений производительности (что почти никогда не бывает), нужно просто создать новую коллекцию с отфильтрованными данными. Ненужная модификация данных часто приводит к целому ряду сложно поддающихся отладке проблем, которых можно избежать, просто сделав эти данные неизменяемыми. Поэтому мы должны использовать только неизменяемые типы коллекций как для аргументов, так и для возвращаемых значений.
Таким образом, у нас остались:
- IEnumerable для аргументов как наиболее общий тип из возможных,
- IReadOnlyList для возвращаемых значений как наиболее конкретный возможный тип.
Мы используем IReadOnlyList вместо IEnumerable, потому что IReadOnlyList обеспечивает больше функциональности: свойство Count, а также доступ к коллекции через индекс.
Замечание: IReadOnlyList не обязательно является неизменяемым «под капотом». Конкретный тип List также реализует IReadOnlyList, и теоретически вы можете привести IReadOnlyList обратно к List и изменить его. Но это привязывает ваш код к деталям реализации метода, возвращающего IReadOnlyList, и делает этот код ненадёжным. Клиентский код не должен полагаться ни на какую информацию, кроме предоставленной сигнатурой метода, и не должен делать никаких предположений об объекте, кроме того, что говорит его тип. Другими словами, никакого даункастинга.
Если вам необходимо изменять возвращаемую коллекцию, просто верните IList вместо IReadOnlyList или создайте новую коллекцию на основе имеющегося IReadOnlyList.
Окончание следует…
Источник: https://enterprisecraftsmanship.com/posts/which-collection-interface-to-use/
Какой Интерфейс Коллекции Использовать? Продолжение
Начало
2. IList и Array
Заметьте, что здесь говорится об интерфейсе IList, а не конкретном типе List. Они почти идентичны с точки зрения функциональности, и поэтому, хотя технически List более конкретен, чем IList, на практике не имеет большого значения, какой из них вы используете.
// вариант 1При принятии решения о том, какой тип использовать в качестве возвращаемого значения, мы не только должны быть осторожны с утечкой абстракций, но также должны учитывать, правильно ли этот тип представляет то, что клиент может и не может делать с возвращаемыми данными.
public IList<Student> GetAll()
// вариант 2
public Student[] GetAll()
Например, клиентский код может изменить список студентов после того, как получит их из репозитория. Вы можете делать это по двум причинам:
- Вы изменяете коллекцию, чтобы добавить или удалить студентов из БД.
- Вы повторно используете коллекцию для других целей. Например, нужно отфильтровать студентов по некоторым критериям, и вместо создания новой коллекции вы удаляете элементы из существующей коллекции.
Обе эти причины неправильные.
Возврат изменяемой коллекции создаёт впечатление, что студентов, которых она представляет, можно изменить, просто добавив или удалив элемент из коллекции, что не так. В тот момент, когда информация о студентах покидает базу данных, эта информация отсоединяется от базы данных, и её изменение ничего не даёт.
Замечание: да, ORM (NHibernate или EF Core) позволяет эмулировать связь объектов с данными в базе, но это не наш случай, когда мы возвращаем коллекцию из метода.
Поэтому мы не должны использовать изменяемую коллекцию, поскольку она не представляет должным образом то, что клиент может и не может делать с данными в БД.
Мы также не должны модифицировать коллекцию, чтобы повторно использовать её для каких-то других целей. Если у вас нет серьёзных ограничений производительности (что почти никогда не бывает), нужно просто создать новую коллекцию с отфильтрованными данными. Ненужная модификация данных часто приводит к целому ряду сложно поддающихся отладке проблем, которых можно избежать, просто сделав эти данные неизменяемыми. Поэтому мы должны использовать только неизменяемые типы коллекций как для аргументов, так и для возвращаемых значений.
Таким образом, у нас остались:
- IEnumerable для аргументов как наиболее общий тип из возможных,
- IReadOnlyList для возвращаемых значений как наиболее конкретный возможный тип.
Мы используем IReadOnlyList вместо IEnumerable, потому что IReadOnlyList обеспечивает больше функциональности: свойство Count, а также доступ к коллекции через индекс.
Замечание: IReadOnlyList не обязательно является неизменяемым «под капотом». Конкретный тип List также реализует IReadOnlyList, и теоретически вы можете привести IReadOnlyList обратно к List и изменить его. Но это привязывает ваш код к деталям реализации метода, возвращающего IReadOnlyList, и делает этот код ненадёжным. Клиентский код не должен полагаться ни на какую информацию, кроме предоставленной сигнатурой метода, и не должен делать никаких предположений об объекте, кроме того, что говорит его тип. Другими словами, никакого даункастинга.
Если вам необходимо изменять возвращаемую коллекцию, просто верните IList вместо IReadOnlyList или создайте новую коллекцию на основе имеющегося IReadOnlyList.
Окончание следует…
Источник: https://enterprisecraftsmanship.com/posts/which-collection-interface-to-use/
👍13
День 1491. #ЗаметкиНаПолях
Какой Интерфейс Коллекции Использовать? Окончание
Начало
Продолжение
3. IEnumerable - тоже дырявая абстракция
В предыдущем посте мы выяснили, что нужно использовать IReadOnlyList в качестве возвращаемого типа коллекции. Но почему так много известных библиотек вместо этого используют IEnumerable?
Одна из причин — ленивая оценка. В .NET BCL большинство инструкций LINQ обрабатываются лениво при работе с IEnumerable:
IEnumerable и ORM
Обратите внимание, что ленивое вычисление также приводит к тому, что IEnumerable в некоторых сценариях является дырявой абстракцией:
IEnumerable без ORM
Реализации IEnumerable часто действуют как дырявые абстракции даже в сценариях без ORM. Например, BlockingCollection реализует IEnumerable таким образом, что он блокирует вызывающий поток в методе MoveNext() до тех пор, пока другой поток не добавит элемент в эту коллекцию. А при реализации «бесконечной» коллекции через yield return вызов ToList на такой коллекции приведёт к зависанию программы в бесконечном цикле. Технически это не дырявая абстракция, т.е. IEnumerable не обещает конечность коллекции, но на практике большинство программистов ожидают от IEnumerable определённого поведения. Можно сказать, что IEnumerable имеет неявный контракт, на который полагаются большинство программистов, и некоторые реализации IEnumerable нарушают его.
IEnumerable в разработке библиотек
Если вы разрабатываете библиотеку для публичного использования, лучше максимально ограничить её публичный API, чтобы дать себе возможность обновлять его. Это включает как количество публичных методов, так и типы, возвращаемые этими методами. Тогда предпочтительнее возвращать IEnumerable вместо IReadOnlyList. Это позволит изменить внутреннюю реализацию, например, List<T> на LinkedList<T>, не нарушая обратной совместимости.
Итого
- Используйте IEnumerable для аргументов как наиболее универсальный тип из возможных.
- Используйте IReadOnlyList для возвращаемых значений как наиболее конкретный возможный тип.
- IQueryable — дырявая абстракция, потому что она требует, чтобы вы знали, какие выражения LINQ может понять ORM.
- IList и Array не подходят, потому что они изменяемы.
- Имейте в виду, что некоторые реализации IEnumerable также являются дырявыми абстракциями.
Источник: https://enterprisecraftsmanship.com/posts/which-collection-interface-to-use/
Какой Интерфейс Коллекции Использовать? Окончание
Начало
Продолжение
3. IEnumerable - тоже дырявая абстракция
В предыдущем посте мы выяснили, что нужно использовать IReadOnlyList в качестве возвращаемого типа коллекции. Но почему так много известных библиотек вместо этого используют IEnumerable?
Одна из причин — ленивая оценка. В .NET BCL большинство инструкций LINQ обрабатываются лениво при работе с IEnumerable:
var numbers = new int[] { 1, 2, 3 };Здесь выполнение 2 и 3 строк откладывается до строки 4, где вызывается Sum. Если нужно поддерживать ленивую оценку, используйте IEnumerable, иначе IReadOnlyList.
var r1 = numbers.Where(x => x > 1);
var r2 = r1.Select(x => x + 1);
int result = r2.Sum();
IEnumerable и ORM
Обратите внимание, что ленивое вычисление также приводит к тому, что IEnumerable в некоторых сценариях является дырявой абстракцией:
// Student repositoryКод в контроллере выполняется только когда вызывается ToList. Если к этому моменту DbContext уже утилизирован, мы получим исключение. Это ещё один пример дырявой абстракции: EF Core требует от вас знать, открыто ли соединение с БД во время оценки IEnumerable. Хотя это не такая уж проблема, поскольку наличие постоянного DbContext является разумным предположением в большинстве веб-приложений. У вас почти всегда будет активный экземпляр DbContext на протяжении всей бизнес-операции.
public IEnumerable<Student> GetAll()
{
using SchoolContext ctx = new();
return ctx.Set<Student>();
}
// контроллер
public IEnumerable<StudentDto> Get()
{
var students = _repo.GetAll();
var dtos = students.Select(MapToDto);
return dtod.ToList();
}
IEnumerable без ORM
Реализации IEnumerable часто действуют как дырявые абстракции даже в сценариях без ORM. Например, BlockingCollection реализует IEnumerable таким образом, что он блокирует вызывающий поток в методе MoveNext() до тех пор, пока другой поток не добавит элемент в эту коллекцию. А при реализации «бесконечной» коллекции через yield return вызов ToList на такой коллекции приведёт к зависанию программы в бесконечном цикле. Технически это не дырявая абстракция, т.е. IEnumerable не обещает конечность коллекции, но на практике большинство программистов ожидают от IEnumerable определённого поведения. Можно сказать, что IEnumerable имеет неявный контракт, на который полагаются большинство программистов, и некоторые реализации IEnumerable нарушают его.
IEnumerable в разработке библиотек
Если вы разрабатываете библиотеку для публичного использования, лучше максимально ограничить её публичный API, чтобы дать себе возможность обновлять его. Это включает как количество публичных методов, так и типы, возвращаемые этими методами. Тогда предпочтительнее возвращать IEnumerable вместо IReadOnlyList. Это позволит изменить внутреннюю реализацию, например, List<T> на LinkedList<T>, не нарушая обратной совместимости.
Итого
- Используйте IEnumerable для аргументов как наиболее универсальный тип из возможных.
- Используйте IReadOnlyList для возвращаемых значений как наиболее конкретный возможный тип.
- IQueryable — дырявая абстракция, потому что она требует, чтобы вы знали, какие выражения LINQ может понять ORM.
- IList и Array не подходят, потому что они изменяемы.
- Имейте в виду, что некоторые реализации IEnumerable также являются дырявыми абстракциями.
Источник: https://enterprisecraftsmanship.com/posts/which-collection-interface-to-use/
👍16
День 1492. #BestPractices
Лучшие Практики Журналирования
Независимо от того, какое ПО вы разрабатываете, вы так или иначе ведёте журнал. Это самый простой инструмент наблюдения, который у нас есть. Есть много ловушек, которые могут привести к бесполезным, объёмным и запутанным журналам. Вот несколько практик, которые позволят писать более качественные и согласованные по всей системе журналы.
Журналы предназначены для разработчиков, вы будете единственным, кто их читает, поэтому, собираясь что-то логировать, спросите себя:
- Поможет ли информация, которую вы собираетесь записать, отладить/понять поток?
- Это нужно писать в журнал? Нельзя ли получить эту информацию из других мест?
- Может ли логируемый объект быть огромным в производственной среде? Если да, можно ли записать только несколько его атрибутов?
Когда вы решите, что писать в журнал, нужно понять, как это делать.
1. Согласованность
Нужно поддерживать согласованность журналов во всей системе. Она ведёт к предсказуемости, что означает, что вы сможете осуществлять поиск по журналу, не вспоминая, в каком формате пишутся логи.
2. Уровень
Важно выбрать правильный уровень журналирования. В .NET определены следующие уровни:
- Trace (0) - наиболее подробные сообщения. Они могут содержать конфиденциальные данные приложения. Этот уровень отключен по умолчанию и никогда не должен включаться в производственной среде.
- Debug (1) - используются для разборов и отладки во время разработки. Они должны в первую очередь содержать информацию, полезную для отладки, и не иметь долгосрочной ценности.
- Information (2) - отслеживают общий поток исполнения приложения. Они должны иметь долгосрочную ценность.
- Warning (3) - выделяют ненормальное или неожиданное событие в потоке приложения, но не приводят к остановке выполнения приложения.
- Error (4) - выделяют, когда текущий поток выполнения останавливается из-за сбоя. Они должны указывать на сбой в текущем действии, а не на сбой всего приложения.
- Critical (5) – описывают неустранимый сбой приложения или системы или катастрофический сбой, требующий немедленного вмешательства.
- None (6) - не используется для записи сообщений журнала. Обозначает уровень на котором не должны записываться никакие сообщения.
Наиболее распространённые ошибки — это ведение слишком подробных журналов уровня Information или полное отсутствие использования уровня Debug.
3. Бережливость
Какой бы сервис логов вы ни использовали, он стоит денег, и быстрый способ сжечь деньги — писать в лог весь объект в виде json, который был относительно небольшим при разработке, но стал огромным в производственной среде. Журналы с огромными объектами бесполезны, их трудно читать, но они существуют, потому что так проще.
Выберите атрибуты, которые являются наиболее важными и полезными для лога и которые действительно помогут вам разобраться в потоке исполнения. Иногда нужно знать, пустой ли объект или его свойство, тогда запишите в лог это, а не сам объект.
4. Уникальность
Каждое сообщение журнала в системе должно быть уникальным. Если я открою журнал конкретного сервиса, я буду сбит с толку, увидев одни и те же логи из разных функций внутри сервиса. Мне будет проще начать отладку проблемы, чем копаться в тысячах одинаковых записей журнала. Т.е. журнал теперь бесполезен. Один из способов сохранить уникальность логов — обозначить имя сервиса и имя функции в качестве префикса для лога. Так гарантируется уникальность или, по крайней мере, сужается область поиска записей со всего сервиса до одной функции.
Итого
Ведение журнала - важный инструмент для любого ПО. Вы будете читать журнал всякий раз, когда нужно разобраться, почему написанный вами код не работает, поэтому не захламляйте его. Избавьте себя от проблем в будущем и заранее инвестируйте в продуманное ведение журнала.
Источник: https://www.16elt.com/2023/01/06/logging-practices-I-follow/
Лучшие Практики Журналирования
Независимо от того, какое ПО вы разрабатываете, вы так или иначе ведёте журнал. Это самый простой инструмент наблюдения, который у нас есть. Есть много ловушек, которые могут привести к бесполезным, объёмным и запутанным журналам. Вот несколько практик, которые позволят писать более качественные и согласованные по всей системе журналы.
Журналы предназначены для разработчиков, вы будете единственным, кто их читает, поэтому, собираясь что-то логировать, спросите себя:
- Поможет ли информация, которую вы собираетесь записать, отладить/понять поток?
- Это нужно писать в журнал? Нельзя ли получить эту информацию из других мест?
- Может ли логируемый объект быть огромным в производственной среде? Если да, можно ли записать только несколько его атрибутов?
Когда вы решите, что писать в журнал, нужно понять, как это делать.
1. Согласованность
Нужно поддерживать согласованность журналов во всей системе. Она ведёт к предсказуемости, что означает, что вы сможете осуществлять поиск по журналу, не вспоминая, в каком формате пишутся логи.
2. Уровень
Важно выбрать правильный уровень журналирования. В .NET определены следующие уровни:
- Trace (0) - наиболее подробные сообщения. Они могут содержать конфиденциальные данные приложения. Этот уровень отключен по умолчанию и никогда не должен включаться в производственной среде.
- Debug (1) - используются для разборов и отладки во время разработки. Они должны в первую очередь содержать информацию, полезную для отладки, и не иметь долгосрочной ценности.
- Information (2) - отслеживают общий поток исполнения приложения. Они должны иметь долгосрочную ценность.
- Warning (3) - выделяют ненормальное или неожиданное событие в потоке приложения, но не приводят к остановке выполнения приложения.
- Error (4) - выделяют, когда текущий поток выполнения останавливается из-за сбоя. Они должны указывать на сбой в текущем действии, а не на сбой всего приложения.
- Critical (5) – описывают неустранимый сбой приложения или системы или катастрофический сбой, требующий немедленного вмешательства.
- None (6) - не используется для записи сообщений журнала. Обозначает уровень на котором не должны записываться никакие сообщения.
Наиболее распространённые ошибки — это ведение слишком подробных журналов уровня Information или полное отсутствие использования уровня Debug.
3. Бережливость
Какой бы сервис логов вы ни использовали, он стоит денег, и быстрый способ сжечь деньги — писать в лог весь объект в виде json, который был относительно небольшим при разработке, но стал огромным в производственной среде. Журналы с огромными объектами бесполезны, их трудно читать, но они существуют, потому что так проще.
Выберите атрибуты, которые являются наиболее важными и полезными для лога и которые действительно помогут вам разобраться в потоке исполнения. Иногда нужно знать, пустой ли объект или его свойство, тогда запишите в лог это, а не сам объект.
4. Уникальность
Каждое сообщение журнала в системе должно быть уникальным. Если я открою журнал конкретного сервиса, я буду сбит с толку, увидев одни и те же логи из разных функций внутри сервиса. Мне будет проще начать отладку проблемы, чем копаться в тысячах одинаковых записей журнала. Т.е. журнал теперь бесполезен. Один из способов сохранить уникальность логов — обозначить имя сервиса и имя функции в качестве префикса для лога. Так гарантируется уникальность или, по крайней мере, сужается область поиска записей со всего сервиса до одной функции.
Итого
Ведение журнала - важный инструмент для любого ПО. Вы будете читать журнал всякий раз, когда нужно разобраться, почему написанный вами код не работает, поэтому не захламляйте его. Избавьте себя от проблем в будущем и заранее инвестируйте в продуманное ведение журнала.
Источник: https://www.16elt.com/2023/01/06/logging-practices-I-follow/
👍12
День 1493. #ЗаметкиНаПолях #TipsAndTricks
Используем Сгенерированное Регулярное Выражение в Ограничениях Маршрута ASP.NET Core
Регулярное выражение на основе сгенерированного кода предоставляет несколько преимуществ по сравнению с традиционным классом Regex:
- Более быстрое время запуска, так как весь код генерируется во время компиляции. Не нужно анализировать шаблон регулярного выражения и генерировать оптимизированный код для выполнения регулярного выражения во время выполнения.
- Улучшенная поддержка тримминга. Код, который не используется, не включается в окончательный бинарный файл.
- Улучшенная поддержка отладки. Вы можете пройтись по коду и посмотреть, что происходит.
Чтобы использовать генератор исходного кода для регулярных выражений, вам необходимы .NET 7 и C# 11. Для стандартных регулярных выражений IDE вроде Visual Studio или Rider даже предложат вам автоматически преобразовать их на использование генераторов кода.
Маршрутизация ASP.NET Core позволяет устанавливать ограничения на параметры маршрута. Ограничение может быть шаблоном регулярного выражения. В большинстве случаев этот шаблон – строковая константа:
Однако ASP.NET Core предоставляет возможность создавать собственные ограничения путем реализации IRouteConstraint или наследования от класса, реализующего этот интерфейс. В этом случае вы можете использовать RegexRouteConstraint и предоставить регулярное выражение в конструкторе:
Используем Сгенерированное Регулярное Выражение в Ограничениях Маршрута ASP.NET Core
Регулярное выражение на основе сгенерированного кода предоставляет несколько преимуществ по сравнению с традиционным классом Regex:
- Более быстрое время запуска, так как весь код генерируется во время компиляции. Не нужно анализировать шаблон регулярного выражения и генерировать оптимизированный код для выполнения регулярного выражения во время выполнения.
- Улучшенная поддержка тримминга. Код, который не используется, не включается в окончательный бинарный файл.
- Улучшенная поддержка отладки. Вы можете пройтись по коду и посмотреть, что происходит.
Чтобы использовать генератор исходного кода для регулярных выражений, вам необходимы .NET 7 и C# 11. Для стандартных регулярных выражений IDE вроде Visual Studio или Rider даже предложат вам автоматически преобразовать их на использование генераторов кода.
Маршрутизация ASP.NET Core позволяет устанавливать ограничения на параметры маршрута. Ограничение может быть шаблоном регулярного выражения. В большинстве случаев этот шаблон – строковая константа:
var builder = WebApplication.CreateBuilder(args);Этот код гарантирует, что параметр value соответствует времени в 24-часовом формате.
var app = builder.Build();
app.UseRouting();
app.MapGet(
"{value:regex(^([01]?[0-9]|2[0-3]):[0-5][0-9]$)}",
(string value) => "Время: " + value);
app.Run();
Однако ASP.NET Core предоставляет возможность создавать собственные ограничения путем реализации IRouteConstraint или наследования от класса, реализующего этот интерфейс. В этом случае вы можете использовать RegexRouteConstraint и предоставить регулярное выражение в конструкторе:
var builder = WebApplication.CreateBuilder(args);Источник: https://www.meziantou.net/using-source-generated-regex-in-asp-net-core-routing.htm
builder.Services.AddRouting(options =>
{
// регистрируем ограничение
options.ConstraintMap.Add(
"time", typeof(TimeRouteConstraint));
});
var app = builder.Build();
app.UseRouting();
app.MapGet(
"{value:time}",
(string value) => "Время: " + value);
app.Run();
sealed partial class TimeRouteConstraint
: RegexRouteConstraint
{
[GeneratedRegex("^([01]?[0-9]|2[0-3]):[0-5][0-9]$")]
private static partial Regex TimeRegex();
public TimeRouteConstraint()
: base(TimeRegex())
{
}
}
👍11
День 1495. #ЧтоНовенького
Выпущена Visual Studio 17.6 Preview 1
Первая превью версия Visual Studio 2022 17.6 уже доступна. Вот некоторые новинки, которые уже можно попробовать.
1. Раскрашивание пар скобок
Теперь вы можете визуально различать наборы открывающих и закрывающих фигурных скобок в вашем коде, что упрощает просмотр области действия вашего кода или поиск недостающих фигурных скобок.
Это доступно в C#, C++, TypeScript, JavaScript, Visual Basic и Razor.
Вы можете включить функцию в Tools > Options > Environment > Preview Features (Инструменты > Параметры > Среда > Предварительный просмотр функций) и отметив флажок Enable Brace Pair Colorization (Включить раскрашивание пар фигурных скобок). См. рисунок 1 ниже.
2. Построчный Git Unstage
В дополнение к построчному Git Stage добавлена функция unstage. См. рисунок 2 ниже.
3. GitHub Issues
Интеграция с GitHub Issues позволяет вам искать и ссылаться на ваши недавние проблемы из окна сообщения коммита в VS. Вы можете сослаться на проблему или пул-реквест, набрав # или нажав кнопку # в нижней правой части текстового поля сообщения коммита. В выпадающем списке будут последние открытые проблемы и пул-реквесты, которые были назначены текущему пользователю, прокомментированы им или в которых он упоминался. См. рисунок 3 ниже. Если вы не прошли аутентификацию в GitHub, вам будет предложено войти в систему, чтобы воспользоваться этой функцией.
Также при изучении истории коммитов в окне репозитория Git вы можете просматривать связанные проблемы и пул-реквесты в области сведений о коммите. Дважды щёлкните на коммит в окне репозитория Git, чтобы открыть сведения. Вы получите дополнительный контекст при просмотре истории Git, чтобы понять, почему произошли изменения. См. рисунок 4 ниже.
4. API примеров использования IntelliCode для C#
Вы когда-нибудь хотели легко найти примеры кода для API, с которыми вы работаете? API примеров использования IntelliCode делает это реальностью. Это функция, позволяющая увидеть реальные примеры того, как другие разработчики использовали данную функцию. Примеры взяты из общедоступных репозиториев с открытым исходным кодом на GitHub. Чтобы использовать эту функцию, наведите указатель мыши на любую поддерживаемую функцию и нажмите ссылку GitHub Examples and Documentation (Примеры и документация на GitHub). См. рисунок 5 ниже.
Источники:
- https://devblogs.microsoft.com/visualstudio/try-visual-studio-2022-v17-6-preview-1/
- https://devblogs.microsoft.com/visualstudio/reference-github-issues-and-pull-requests-in-visual-studio/
Выпущена Visual Studio 17.6 Preview 1
Первая превью версия Visual Studio 2022 17.6 уже доступна. Вот некоторые новинки, которые уже можно попробовать.
1. Раскрашивание пар скобок
Теперь вы можете визуально различать наборы открывающих и закрывающих фигурных скобок в вашем коде, что упрощает просмотр области действия вашего кода или поиск недостающих фигурных скобок.
Это доступно в C#, C++, TypeScript, JavaScript, Visual Basic и Razor.
Вы можете включить функцию в Tools > Options > Environment > Preview Features (Инструменты > Параметры > Среда > Предварительный просмотр функций) и отметив флажок Enable Brace Pair Colorization (Включить раскрашивание пар фигурных скобок). См. рисунок 1 ниже.
2. Построчный Git Unstage
В дополнение к построчному Git Stage добавлена функция unstage. См. рисунок 2 ниже.
3. GitHub Issues
Интеграция с GitHub Issues позволяет вам искать и ссылаться на ваши недавние проблемы из окна сообщения коммита в VS. Вы можете сослаться на проблему или пул-реквест, набрав # или нажав кнопку # в нижней правой части текстового поля сообщения коммита. В выпадающем списке будут последние открытые проблемы и пул-реквесты, которые были назначены текущему пользователю, прокомментированы им или в которых он упоминался. См. рисунок 3 ниже. Если вы не прошли аутентификацию в GitHub, вам будет предложено войти в систему, чтобы воспользоваться этой функцией.
Также при изучении истории коммитов в окне репозитория Git вы можете просматривать связанные проблемы и пул-реквесты в области сведений о коммите. Дважды щёлкните на коммит в окне репозитория Git, чтобы открыть сведения. Вы получите дополнительный контекст при просмотре истории Git, чтобы понять, почему произошли изменения. См. рисунок 4 ниже.
4. API примеров использования IntelliCode для C#
Вы когда-нибудь хотели легко найти примеры кода для API, с которыми вы работаете? API примеров использования IntelliCode делает это реальностью. Это функция, позволяющая увидеть реальные примеры того, как другие разработчики использовали данную функцию. Примеры взяты из общедоступных репозиториев с открытым исходным кодом на GitHub. Чтобы использовать эту функцию, наведите указатель мыши на любую поддерживаемую функцию и нажмите ссылку GitHub Examples and Documentation (Примеры и документация на GitHub). См. рисунок 5 ниже.
Источники:
- https://devblogs.microsoft.com/visualstudio/try-visual-studio-2022-v17-6-preview-1/
- https://devblogs.microsoft.com/visualstudio/reference-github-issues-and-pull-requests-in-visual-studio/
👍5