День семьсот шестьдесят второй. #ЗаметкиНаПолях #SQL
На третьем году существования канала я понял, что есть один язык, который я незаслуженно обходил вниманием. Восполняю упущение. Начинаю новую серию постов про SQL. Думаю, что основные основы читателям моего канала объяснять не надо (если надо, пишите в комментариях, что интересно), поэтому буду писать о «фишках». Проблема в том, что они различаются как по наличию в разных СУБД, так и по синтаксису. Поэтому буду стараться выбирать более-менее универсальные вещи и описывать концепцию, а не особенности синтаксиса.
Возвращение Данных из DML Запроса
Поначалу это может показаться странным, но возможность возвращать данные из DML - очень полезная функция.
- В запросе INSERT:
Наиболее распространённый вариант использования - получение автоматически сгенерированных значений. Например, ключей для создания записей в дочерних таблицах. Кроме того, возвращённые таким образом данные могут использоваться для аудита или логирования запросов.
- В запросе UPDATE:
Здесь выражение это используется не так часто, но всё же возможно его применение для получения значений по умолчанию, заданных в базе данных, либо для аудита запросов.
- В запросе DELETE:
Совсем редкий случай использования, в основном для целей аудита, либо, возможно, переноса данных в архивную таблицу, хотя так лучше не делать.
СУБД: Oracle, PostgreSQL, MariaDB
Выражение:
Выражение:
Пример:
- https://app.pluralsight.com/library/courses/postgresql-data-manipulation-playbook/
- https://docs.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql
На третьем году существования канала я понял, что есть один язык, который я незаслуженно обходил вниманием. Восполняю упущение. Начинаю новую серию постов про SQL. Думаю, что основные основы читателям моего канала объяснять не надо (если надо, пишите в комментариях, что интересно), поэтому буду писать о «фишках». Проблема в том, что они различаются как по наличию в разных СУБД, так и по синтаксису. Поэтому буду стараться выбирать более-менее универсальные вещи и описывать концепцию, а не особенности синтаксиса.
Возвращение Данных из DML Запроса
Поначалу это может показаться странным, но возможность возвращать данные из DML - очень полезная функция.
- В запросе INSERT:
Наиболее распространённый вариант использования - получение автоматически сгенерированных значений. Например, ключей для создания записей в дочерних таблицах. Кроме того, возвращённые таким образом данные могут использоваться для аудита или логирования запросов.
- В запросе UPDATE:
Здесь выражение это используется не так часто, но всё же возможно его применение для получения значений по умолчанию, заданных в базе данных, либо для аудита запросов.
- В запросе DELETE:
Совсем редкий случай использования, в основном для целей аудита, либо, возможно, переноса данных в архивную таблицу, хотя так лучше не делать.
СУБД: Oracle, PostgreSQL, MariaDB
Выражение:
RETURNING
Синтаксис:INSERT INTO | UPDATE | DELETE FROM table …Выражение
RETURNING expression1 [INTO variable1]
[, expression2 [INTO variable2]] …;
INTO variable1
позволяет вставить возвращённое значение в переменную в хранимой процедуре. Возвращать значения можно как в переменные примитивных типов, так в целую строку, используя пользовательский тип:my_row mytable%ROWTYPE;Пример:
…
RETURNING * INTO my_row;
INSERT INTO users (firstname, lastname)СУБД: MsSQL
VALUES ('Joe', 'Cool') RETURNING id;
Выражение:
OUTPUT
Синтаксис:INSERT INTO | UPDATE | DELETE FROM table …В MsSQL также можно обратиться к псевдотаблицам
OUTPUT INSERTED.expression1 [INTO variable1]
[, DELETED.expression2 [INTO variable2]] …;
INSERTED
и DELETED
. В запросе UPDATE
– DELETED
представляет заменяемое значение, INSERTED
представляет новое значение поля. В запросах INSERT
и DELETE
используется соответствующая псевдотаблица.Пример:
DELETE Sales.ShoppingCartItemИсточники:
OUTPUT DELETED.*;
- https://app.pluralsight.com/library/courses/postgresql-data-manipulation-playbook/
- https://docs.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql
День семьсот шестьдесят четвёртый. #BestPractices
9 «Правил» Более Чистого Кода
Следующие 9 правил относятся ко всем объектно-ориентированным языкам. Изначально они были описаны в книге Джеффа Бея «The Thoughtworks Anthology» как «Object Calisthenics» (слишком мудрёные выражения, я даже не буду пытаться их перевести, чтобы вас не путать). Правила эти, как пиратский кодекс, скорее являются рекомендациями, чем строгими законами, и, конечно, подразумевают наличие исключений. Кроме того, со многими из них можно спорить (что и призываю вас делать в комментариях).
1. Один уровень вложенности на метод
Не плодите длинные методы, в которых условные операторы содержат циклы, содержащие вложенные циклы, содержащие условные операторы. Верхний уровень кода – нулевой, код внутри цикла или условного оператора – первый уровень вложенности. Всё! Код из более высоких уровней вложенности нужно выделить в отдельный метод. Исключение – однострочные операторы,
2. Не используйте ключевое слово else
Спорное правило. Дело не в том, что нужно срочно очистить код от всех упоминаний
- используя тернарный оператор:
и т.п.
3. Оборачивайте все примитивные типы и строки
Если коротко, то суть состоит в том, чтобы не использовать примитивные типы в качестве объектов домена. А использовать вместо этого специальные типы. Например, не использовать строку или число для почтового индекса. Индекс имеет определённый формат, а поэтому должен иметь и проверку правильности введённого значения, которую лучше реализовать внутри объекта индекса.
4. Полноправные коллекции
Это правило призывает создавать отдельный класс для коллекций из непримитивных типов. Например,
5. Одна точка на строку
За исключением паттерна Строитель, LINQ или Fluent API, не увлекайтесь длинными цепочками методов или свойств. Лучше разделить их на несколько переменных. Это поможет как чтению кода, так и отладке, т.к. можно будет остановить выполнение на любой строке, чего нельзя сделать в цепочке вызовов.
6. Не используйте аббревиатуры
Не ленитесь печатать полные имена методов и переменных. Ваши коллеги или вы же из будущего скажут вам спасибо.
7. Сохраняйте небольшой размер сущностей
Тут могут быть разные советы и корпоративные стандарты на размер класса в строках или количестве методов. Но главное, не нарушайте Принцип Единственной Ответственности. Ну и насторожитесь, если класс длиннее 250 строк.
8. Не внедряйте в класс больше двух зависимостей
Это тоже довольно спорное и, наверное, слишком строгое ограничение. Например, здесь можно не учитывать логгеры или другие зависимости, требуемые для отладки. Но в общем случае, когда вы обнаруживаете, что в классе 5 и более зависимостей, то, наверное, он делает слишком много.
9. Не злоупотребляйте свойствами
Скажу честно, в оригинале это звучит как «Никаких геттеров/сеттеров/свойств», но это уже чересчур. Однако доля истины в этом правиле есть. Не позволяйте внешнему коду бездумно менять значения свойств класса. Если в классе есть счётчик, не дело внешнего кода произвольно менять его значение. Когда счётчик нужно увеличить, пусть внешний код вызывает специальный метод, который это делает.
Источник: https://youtu.be/gyrSiY4SHxI
9 «Правил» Более Чистого Кода
Следующие 9 правил относятся ко всем объектно-ориентированным языкам. Изначально они были описаны в книге Джеффа Бея «The Thoughtworks Anthology» как «Object Calisthenics» (слишком мудрёные выражения, я даже не буду пытаться их перевести, чтобы вас не путать). Правила эти, как пиратский кодекс, скорее являются рекомендациями, чем строгими законами, и, конечно, подразумевают наличие исключений. Кроме того, со многими из них можно спорить (что и призываю вас делать в комментариях).
1. Один уровень вложенности на метод
Не плодите длинные методы, в которых условные операторы содержат циклы, содержащие вложенные циклы, содержащие условные операторы. Верхний уровень кода – нулевой, код внутри цикла или условного оператора – первый уровень вложенности. Всё! Код из более высоких уровней вложенности нужно выделить в отдельный метод. Исключение – однострочные операторы,
return
, continue
и т.п. Это сильно улучшит читаемость кода.2. Не используйте ключевое слово else
Спорное правило. Дело не в том, что нужно срочно очистить код от всех упоминаний
else
. Просто на самом деле в большинстве случаев можно обойтись без него:- используя тернарный оператор:
var a = (x >= 0 ? "positive" : "negative");- задавая изначальное значение переменной перед
if
:var a = "negative";- используя return в блоке
if (x >= 0) a = "positive";
if
(тогда код после блока if
будет выполняться, как если бы он был в else
)и т.п.
3. Оборачивайте все примитивные типы и строки
Если коротко, то суть состоит в том, чтобы не использовать примитивные типы в качестве объектов домена. А использовать вместо этого специальные типы. Например, не использовать строку или число для почтового индекса. Индекс имеет определённый формат, а поэтому должен иметь и проверку правильности введённого значения, которую лучше реализовать внутри объекта индекса.
4. Полноправные коллекции
Это правило призывает создавать отдельный класс для коллекций из непримитивных типов. Например,
Dictionary<Guid, Client>
. На первый взгляд это простой словарь клиентов. Но ответьте на вопрос: позволено ли коду, использующему этот словарь, напрямую изменять его или изменять его элементы? Скорее всего нет. Таким образом эта коллекция сама должна стать полноправной сущностью домена со своими правилами обращения с элементами.5. Одна точка на строку
За исключением паттерна Строитель, LINQ или Fluent API, не увлекайтесь длинными цепочками методов или свойств. Лучше разделить их на несколько переменных. Это поможет как чтению кода, так и отладке, т.к. можно будет остановить выполнение на любой строке, чего нельзя сделать в цепочке вызовов.
6. Не используйте аббревиатуры
Не ленитесь печатать полные имена методов и переменных. Ваши коллеги или вы же из будущего скажут вам спасибо.
7. Сохраняйте небольшой размер сущностей
Тут могут быть разные советы и корпоративные стандарты на размер класса в строках или количестве методов. Но главное, не нарушайте Принцип Единственной Ответственности. Ну и насторожитесь, если класс длиннее 250 строк.
8. Не внедряйте в класс больше двух зависимостей
Это тоже довольно спорное и, наверное, слишком строгое ограничение. Например, здесь можно не учитывать логгеры или другие зависимости, требуемые для отладки. Но в общем случае, когда вы обнаруживаете, что в классе 5 и более зависимостей, то, наверное, он делает слишком много.
9. Не злоупотребляйте свойствами
Скажу честно, в оригинале это звучит как «Никаких геттеров/сеттеров/свойств», но это уже чересчур. Однако доля истины в этом правиле есть. Не позволяйте внешнему коду бездумно менять значения свойств класса. Если в классе есть счётчик, не дело внешнего кода произвольно менять его значение. Когда счётчик нужно увеличить, пусть внешний код вызывает специальный метод, который это делает.
Источник: https://youtu.be/gyrSiY4SHxI
День семьсот шестьдесят пятый. #Оффтоп
Почти год назад я писал про новую функцию языка C# - Генераторы Кода. И вот постепенно начали появляться интересные реализации, использующие их, например Mapster.
Но всё-таки до сих пор не было подробного объяснения, что это, как это всё работает, в чём плюсы и минусы, где их можно использовать и т.п. И вот недавно в открытый доступ выложили видео с последней конференции DotNext «Source Generators в действии» от Андрея Дятлова https://youtu.be/6QWZds35rGs
«В докладе вы узнаете не только о том, что скрывается за термином «Source Generators» и как его использовать, но и о том, как предоставить пользователю вашего генератора необходимую гибкость конфигурации и понятные сообщения о возникающих проблемах. Генерация кода по праву считается областью, в которой трудно понять, что пошло не так, покрыть программу тестами или взглянуть на полученный код под отладчиком. Это удерживает многих программистов от её использования, и в докладе Андрей расскажет о том, как с этим справляются генераторы. Тех, кто уже давно пользуется существующими технологиями метапрограммирования на практике, заинтересует, какие сценарии остались не поддержанными в C# 9 и сравнение новых возможностей с существующими технологиями (Fody, PostSharp, T4 и пр). Остались ли у них уникальные ниши и преимущества или же будущее за генераторами?»
Мне видео понравилось. Только имейте в виду, что требуется достаточно глубокий уровень знаний языка, чтобы более-менее понимать. Я частенько терял мысль.
Почти год назад я писал про новую функцию языка C# - Генераторы Кода. И вот постепенно начали появляться интересные реализации, использующие их, например Mapster.
Но всё-таки до сих пор не было подробного объяснения, что это, как это всё работает, в чём плюсы и минусы, где их можно использовать и т.п. И вот недавно в открытый доступ выложили видео с последней конференции DotNext «Source Generators в действии» от Андрея Дятлова https://youtu.be/6QWZds35rGs
«В докладе вы узнаете не только о том, что скрывается за термином «Source Generators» и как его использовать, но и о том, как предоставить пользователю вашего генератора необходимую гибкость конфигурации и понятные сообщения о возникающих проблемах. Генерация кода по праву считается областью, в которой трудно понять, что пошло не так, покрыть программу тестами или взглянуть на полученный код под отладчиком. Это удерживает многих программистов от её использования, и в докладе Андрей расскажет о том, как с этим справляются генераторы. Тех, кто уже давно пользуется существующими технологиями метапрограммирования на практике, заинтересует, какие сценарии остались не поддержанными в C# 9 и сравнение новых возможностей с существующими технологиями (Fody, PostSharp, T4 и пр). Остались ли у них уникальные ниши и преимущества или же будущее за генераторами?»
Мне видео понравилось. Только имейте в виду, что требуется достаточно глубокий уровень знаний языка, чтобы более-менее понимать. Я частенько терял мысль.
День семьсот шестьдесят шестой. #ЧтоНовенького
Что нового в Visual Studio 2019 v16.10 Preview 1
В Microsoft объявили о долгосрочной поддержке релиза Visual Studio 2019 версии 16.9, а также о выходе первой предварительной версии 16.10. О новых функциях версии 16.9 я уже писал здесь и здесь, поэтому сегодня о 16.10, где есть пара интересных новинок.
1. Удаление неиспользуемых ссылок
Добавлена возможность удалить из проекта неиспользуемые ссылки на проекты и пакеты NuGet. Это можно сделать из контекстного меню проекта «Удалить Неиспользуемые Ссылки» (Remove Unused References). По умолчанию эта возможность отключена, но её можно включить в меню Инструменты > Параметры > Текстовый редактор > C# > Дополнительно (Tools > Options > Text Editor > C# > Advanced). Отметьте команду «Удалить неиспользуемые ссылки» (Remove Unused References). После выбора этого пункта контекстного меню откроется диалоговое окно, где вы сможете просмотреть все ссылки, которые будут удалены, и отметить те, которые вы хотите сохранить. См. рис. 1 ниже.
2. Упрощение выражений LINQ
Эти подсказки рефакторинга предложат вам, например, удалить лишний вызов метода .Where(), чтобы повысить производительность и читаемость. Подсказка появляется, если поместить курсор на выражение LINQ и нажать
3. Новые варианты автозавершения
IntelliSense теперь будет предлагать среди вариантов завершения значения
Также в меню Инструменты > Параметры > Текстовый редактор > Дополнительно (Tools > Options > Text Editor > Advanced) можно настроить режим автозавершения только по Tab, автоматически (по точке, скобке и т.п.) или по последнему сохранённому значению.
Кроме того, новая команда «Умный Перевод Строки» (Smart Break Line) автоматически вставит фигурные скобки и поставит курсор между ними при нажатии
4. Настройки стилей кодирования для пустых строк
Вы можете настроить обработку пустых строк в файле EditorConfig или в меню Инструменты > Параметры > Текстовый редактор> C# > Стиль кода > Параметры новых строк (Tools > Options > Text Editor > C# > Code Style > New line preferences). Например, вы можете настроить, допустимы ли несколько пустых строк подряд, допустим ли код сразу после закрывающей фигурной скобки блока и т.п. Для каждого параметра можно настроить, будет ли он исправляться при рефакторинге или выдавать предложение, предупреждение или ошибку. См. рис. 4 ниже.
Установить Visual Studio 2019 v16.10 Preview 1
Источник: https://devblogs.microsoft.com/visualstudio/vs2019-v16-9-and-v16-10-preview-1/
Что нового в Visual Studio 2019 v16.10 Preview 1
В Microsoft объявили о долгосрочной поддержке релиза Visual Studio 2019 версии 16.9, а также о выходе первой предварительной версии 16.10. О новых функциях версии 16.9 я уже писал здесь и здесь, поэтому сегодня о 16.10, где есть пара интересных новинок.
1. Удаление неиспользуемых ссылок
Добавлена возможность удалить из проекта неиспользуемые ссылки на проекты и пакеты NuGet. Это можно сделать из контекстного меню проекта «Удалить Неиспользуемые Ссылки» (Remove Unused References). По умолчанию эта возможность отключена, но её можно включить в меню Инструменты > Параметры > Текстовый редактор > C# > Дополнительно (Tools > Options > Text Editor > C# > Advanced). Отметьте команду «Удалить неиспользуемые ссылки» (Remove Unused References). После выбора этого пункта контекстного меню откроется диалоговое окно, где вы сможете просмотреть все ссылки, которые будут удалены, и отметить те, которые вы хотите сохранить. См. рис. 1 ниже.
2. Упрощение выражений LINQ
Эти подсказки рефакторинга предложат вам, например, удалить лишний вызов метода .Where(), чтобы повысить производительность и читаемость. Подсказка появляется, если поместить курсор на выражение LINQ и нажать
Ctrl+.
См. рис. 2 ниже.3. Новые варианты автозавершения
IntelliSense теперь будет предлагать среди вариантов завершения значения
enum
, когда тип известен, даже если вы не вводите название самого перечисления. Просто начните вводить название значения, и оно появится в подсказке. См. рис. 3 ниже.Также в меню Инструменты > Параметры > Текстовый редактор > Дополнительно (Tools > Options > Text Editor > Advanced) можно настроить режим автозавершения только по Tab, автоматически (по точке, скобке и т.п.) или по последнему сохранённому значению.
Кроме того, новая команда «Умный Перевод Строки» (Smart Break Line) автоматически вставит фигурные скобки и поставит курсор между ними при нажатии
Shift+Enter
после объявления названия типа, метода, свойства, события и т.п. Повторное нажатие Shift+Enter
уберёт скобки и добавит точку с запятой в конце строки.4. Настройки стилей кодирования для пустых строк
Вы можете настроить обработку пустых строк в файле EditorConfig или в меню Инструменты > Параметры > Текстовый редактор> C# > Стиль кода > Параметры новых строк (Tools > Options > Text Editor > C# > Code Style > New line preferences). Например, вы можете настроить, допустимы ли несколько пустых строк подряд, допустим ли код сразу после закрывающей фигурной скобки блока и т.п. Для каждого параметра можно настроить, будет ли он исправляться при рефакторинге или выдавать предложение, предупреждение или ошибку. См. рис. 4 ниже.
Установить Visual Studio 2019 v16.10 Preview 1
Источник: https://devblogs.microsoft.com/visualstudio/vs2019-v16-9-and-v16-10-preview-1/
День семьсот шестьдесят седьмой. #Оффтоп #ЗадачиНаСобеседовании
Давненько у нас не было задач.
Допустим, вы ищете квартиру. Для простоты представим улицу в виде одномерного массива кварталов. Пусть у нас будет только одна улица в городе, идеально прямая, а расстояния между кварталами одинаковы и равны 1.
В каждом квартале есть подходящая вам квартира. Кроме того, в кварталах случайным образом расположены важные для вас объекты: магазин, тренажёрный зал, школа для ребёнка и т.п. Допустим, что они одинаково для вас важны. Идеальная для вас квартира находится квартале с наименьшим расстоянием до самого дальнего важного объекта. Обратите внимание: не с минимальной суммой расстояний до всех объектов, а с минимальным наибольшим расстоянием! Задача – найти такой квартал.
Кварталы даны в виде массива словарей (не пугайтесь, это для наглядности, и чтобы не создавать кучи сущностей 😊). В словаре ключ – строковое название объекта, и логическое значение есть он в квартале или нет. Например, вот так:
Таким образом, в первом квартале дальше всего идти до школы - 4. А победителем получается квартал №4. Хотя там ничего нет, но из него до всех объектов расстояние 1.
Для простоты допустим, что кварталов всегда больше одного, и во всех кварталах заданы все нужные вам объекты (которых в принципе может быть сколько угодно). А при равенстве результатов можно выдать первый.
На этот раз у меня для вас есть даже шаблон проекта с тестами: https://github.com/sbzenenko/NetDeveloper/tree/main/ApartmentFinder
Всё, что вам надо сделать – реализовать метод
Вопросы и предложения оставляйте в комментариях. Через пару дней выложу решение с объяснением.
Давненько у нас не было задач.
Допустим, вы ищете квартиру. Для простоты представим улицу в виде одномерного массива кварталов. Пусть у нас будет только одна улица в городе, идеально прямая, а расстояния между кварталами одинаковы и равны 1.
В каждом квартале есть подходящая вам квартира. Кроме того, в кварталах случайным образом расположены важные для вас объекты: магазин, тренажёрный зал, школа для ребёнка и т.п. Допустим, что они одинаково для вас важны. Идеальная для вас квартира находится квартале с наименьшим расстоянием до самого дальнего важного объекта. Обратите внимание: не с минимальной суммой расстояний до всех объектов, а с минимальным наибольшим расстоянием! Задача – найти такой квартал.
Кварталы даны в виде массива словарей (не пугайтесь, это для наглядности, и чтобы не создавать кучи сущностей 😊). В словаре ключ – строковое название объекта, и логическое значение есть он в квартале или нет. Например, вот так:
[То есть, в первом квартале нет тренажёрного зала и школы, но есть магазин. Во втором есть только тренажёрный зал. В третьем – зал и магазин. И т.д.
{{"gym",false},{"school",false},{"store",true}},
{{"gym",true },{"school",false},{"store",false}},
{{"gym",true },{"school",false},{"store",true}},
{{"gym",false },{"school",false},{"store",false}},
{{"gym",false },{"school",true},{"store",true}}
]
Таким образом, в первом квартале дальше всего идти до школы - 4. А победителем получается квартал №4. Хотя там ничего нет, но из него до всех объектов расстояние 1.
Для простоты допустим, что кварталов всегда больше одного, и во всех кварталах заданы все нужные вам объекты (которых в принципе может быть сколько угодно). А при равенстве результатов можно выдать первый.
На этот раз у меня для вас есть даже шаблон проекта с тестами: https://github.com/sbzenenko/NetDeveloper/tree/main/ApartmentFinder
Всё, что вам надо сделать – реализовать метод
Find()
, принимающий массив кварталов и возвращающий индекс идеального квартала.Вопросы и предложения оставляйте в комментариях. Через пару дней выложу решение с объяснением.
День семьсот шестьдесят восьмой. #ЗаметкиНаПолях
Обнуляемый null
Рассмотрим следующий код:
Раньше оператор
Свойство
Таким образом программист сообщает компилятору, что он уверен, что здесь значение переменной не будет
Можно рассматривать операторы
Например:
ВНИМАНИЕ: оператор
Использование оператора
Зачем тогда он нужен?
Существуют допустимые варианты использования, в которых использование является целесообразным:
- В некоторых (редких) случаях компилятор не может определить, что обнуляемое значение на самом деле не может быть
- Для упрощения миграции старого кода, не использовавшего обнуляемые ссылочные типы.
- В некоторых случаях вас просто не волнует, что что-то будет
- В тестах для проверки поведения кода при получении
Так что же такое
Систему типов не волнует фактическое значении переменной во время выполнения. Её заботит только тип переменной времени компиляции. И в исходном примере свойство
Источник: https://stackoverflow.com/questions/54724304/what-does-null-statement-mean
Обнуляемый null
Рассмотрим следующий код:
public class Person {Что значит
public string FirstName { get; }
public string LastName { get; } = null!;
public string? MiddleName {get; } = null;
public Person (string first,
string last, string? middle) {
FirstName = first;
LastName = last;
MiddleName = middle;
}
}
null!
?Раньше оператор
!
означал отрицание в логических выражениях. Но начиная с C#8 в языке допустимо использование обнуляемых ссылочных типов. Поэтому оператор !
приобрёл другое значение и стал называться null-снисходительным (null-forgiving). Свойство
MiddleName
обнуляемое (string?
), т.к. у человека может не быть отчества. Тогда:Console.WriteLine(person.MiddleName.Length);выдаст предупреждение, что
MiddleName
может быть null
, аConsole.WriteLine(person.MiddleName!.Length);не выдаст предупреждения из-за null-снисходительного оператора.
Таким образом программист сообщает компилятору, что он уверен, что здесь значение переменной не будет
null
.Можно рассматривать операторы
?
и !
как приведение типов?
= из необнуляемого в обнуляемый!
= из обнуляемого в необнуляемыйНапример:
string? x;
?
делает из необнуляемого string
обнуляемый тип, поэтому можно использовать x = null
.string y;Здесь
y = null
приводит к предупреждению компилятора, из-за присваивания null
необнуляемому типу. Аналогично y = x приведёт к предупреждению, т.к. x может быть null
. Однако y = x!
не вызовет предупреждения, т.к. мы «гарантируем», что x
не null
.ВНИМАНИЕ: оператор
!
отключает только проверку компилятора на уровне системы типов. Во время выполнения значение может быть null. Поэтому использование null-снисходительного оператора может быть признаком плохого дизайна системы, поскольку он сводит на нет все усилия проверки на null-безопасность, которую выполняет компилятор.Использование оператора
!
может создать очень трудные для поиска ошибки. Если у вас есть свойство, помеченное как необнуляемое, предполагается, что его можно использовать безопасно. Но во время выполнения вы можете неожиданно столкнуться с исключением NullReferenceException
, поскольку значение фактически стало null
из-за обхода проверок компилятора с помощью оператора !
.Зачем тогда он нужен?
Существуют допустимые варианты использования, в которых использование является целесообразным:
- В некоторых (редких) случаях компилятор не может определить, что обнуляемое значение на самом деле не может быть
null
.- Для упрощения миграции старого кода, не использовавшего обнуляемые ссылочные типы.
- В некоторых случаях вас просто не волнует, что что-то будет
null
.- В тестах для проверки поведения кода при получении
null
.Так что же такое
null!
?null!
сообщает компилятору, что null
не допускает значения null
. Странно, правда? Но это то же самое, что и x! из примера выше. Литерал null допускает значение null
по определению. Но, как мы узнали, обнуляемость любого типа можно переопределить с помощью оператора !
.Систему типов не волнует фактическое значении переменной во время выполнения. Её заботит только тип переменной времени компиляции. И в исходном примере свойство
LastName
(null!
) не допускает значения null
, что допустимо для системы типов.Источник: https://stackoverflow.com/questions/54724304/what-does-null-statement-mean
День семьсот шестьдесят девятый. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
79. Используйте Анализаторы Кода
Ценность тестирования - вот что вбивают в головы разработчикам ПО с ранних этапов их пути в программировании. В последние годы рост модульного тестирования, разработки, основанной на тестировании, и agile методов свидетельствует о всплеске интереса к максимальному использованию тестирования на всех этапах цикла разработки. Однако тестирование - это лишь один из многих инструментов, которые можно использовать для улучшения качества кода.
В далеком прошлом, когда C был ещё новинкой, процессорное время и память любого типа были в дефиците. Первые компиляторы C знали об этом и поэтому сокращали количество проходов через код, которые они выполняли, исключая некоторые семантические проверки. То есть компилятор проверял только небольшое подмножество ошибок, которые могли быть обнаружены во время компиляции. Чтобы компенсировать это, Стивен Джонсон написал инструмент под названием lint (он удалял мусор из вашего кода), который реализовал некоторые статические проверки, удалённые из компилятора. Однако инструменты статического анализа приобрели сомнительную репутацию из-за того, что выдавали большое количество ложноположительных предупреждений и замечаний о стилистических соглашениях, которые не всегда необходимо соблюдать.
Нынешнее состояние языков, компиляторов и инструментов статического анализа сильно отличается. Память и время процессора теперь относительно дёшевы, поэтому компиляторы могут позволить себе проверять больше ошибок. Практически каждый язык может похвастаться по крайней мере одним инструментом, проверяющим наличие нарушений соглашений по стилю, распространённые ошибки, а иногда и наличие хитрых ошибок, которые трудно обнаружить, например, потенциальное присваивание null.
Более сложные инструменты, такие как Splint для C, Pylint для Python или анализаторы Roslyn для .NET настраиваются. То есть вы можете выбрать, какие ошибки и предупреждения будет выдавать инструмент, с помощью файла конфигурации, в командной строке или в вашей IDE. В некоторых случаях можно писать аннотации для анализатора прямо в коде.
Если всё остальное не помогает, и вы обнаруживаете, что вручную ищете простые ошибки или нарушения стандартов, которые не обнаруживаются вашим компилятором, IDE или инструментами статического анализа, вы всегда можете реализовать свою собственную статическую проверку. Это не так сложно, как может показаться. Большинство языков, особенно динамических, предоставляют абстрактное синтаксическое дерево и инструменты компиляции как часть своей стандартной библиотеки. Стоит познакомиться с малоиспользуемыми функциями стандартных библиотек, которые используются командой разработчиков языка, поскольку они часто содержат мощный функционал полезный для статического анализа и динамического тестирования.
Не позволяйте тестированию быть единственной гарантией качества вашего кода. Воспользуйтесь существующими инструментами анализа и не бойтесь создавать свои собственные.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Sarah Mount
97 Вещей, Которые Должен Знать Каждый Программист
79. Используйте Анализаторы Кода
Ценность тестирования - вот что вбивают в головы разработчикам ПО с ранних этапов их пути в программировании. В последние годы рост модульного тестирования, разработки, основанной на тестировании, и agile методов свидетельствует о всплеске интереса к максимальному использованию тестирования на всех этапах цикла разработки. Однако тестирование - это лишь один из многих инструментов, которые можно использовать для улучшения качества кода.
В далеком прошлом, когда C был ещё новинкой, процессорное время и память любого типа были в дефиците. Первые компиляторы C знали об этом и поэтому сокращали количество проходов через код, которые они выполняли, исключая некоторые семантические проверки. То есть компилятор проверял только небольшое подмножество ошибок, которые могли быть обнаружены во время компиляции. Чтобы компенсировать это, Стивен Джонсон написал инструмент под названием lint (он удалял мусор из вашего кода), который реализовал некоторые статические проверки, удалённые из компилятора. Однако инструменты статического анализа приобрели сомнительную репутацию из-за того, что выдавали большое количество ложноположительных предупреждений и замечаний о стилистических соглашениях, которые не всегда необходимо соблюдать.
Нынешнее состояние языков, компиляторов и инструментов статического анализа сильно отличается. Память и время процессора теперь относительно дёшевы, поэтому компиляторы могут позволить себе проверять больше ошибок. Практически каждый язык может похвастаться по крайней мере одним инструментом, проверяющим наличие нарушений соглашений по стилю, распространённые ошибки, а иногда и наличие хитрых ошибок, которые трудно обнаружить, например, потенциальное присваивание null.
Более сложные инструменты, такие как Splint для C, Pylint для Python или анализаторы Roslyn для .NET настраиваются. То есть вы можете выбрать, какие ошибки и предупреждения будет выдавать инструмент, с помощью файла конфигурации, в командной строке или в вашей IDE. В некоторых случаях можно писать аннотации для анализатора прямо в коде.
Если всё остальное не помогает, и вы обнаруживаете, что вручную ищете простые ошибки или нарушения стандартов, которые не обнаруживаются вашим компилятором, IDE или инструментами статического анализа, вы всегда можете реализовать свою собственную статическую проверку. Это не так сложно, как может показаться. Большинство языков, особенно динамических, предоставляют абстрактное синтаксическое дерево и инструменты компиляции как часть своей стандартной библиотеки. Стоит познакомиться с малоиспользуемыми функциями стандартных библиотек, которые используются командой разработчиков языка, поскольку они часто содержат мощный функционал полезный для статического анализа и динамического тестирования.
Не позволяйте тестированию быть единственной гарантией качества вашего кода. Воспользуйтесь существующими инструментами анализа и не бойтесь создавать свои собственные.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Sarah Mount
День семьсот семидесятый. #Оффтоп #ЗадачиНаСобеседовании
Ответ на задачу про поиск квартиры.
Создадим двумерный массив для хранения расстояний. В строках будут кварталы, в столбцах объекты. При этом, если объект присутствует в квартале, отметим соответствующее расстояние как 0, если нет, для начала отметим его недостижимо большим значением, например,
1. Задаём значение расстояния как минимальное между существующим значением и значением на 1 больше, чем в предыдущем квартале. То есть, если, проходя в одну сторону, мы получили расстояние до объекта в 3 квартала, но он находится в следующем квартале, то, проходя в обратную сторону, мы зададим минимальное расстояние между 3 и 1 – 1. Аналогичным образом мы заменим все большие значение, обозначенные
2. Кроме того, рассчитав все расстояния в квартале, считаем максимальное из них.
Таким образом, нам нужно дважды пройти массив кварталов, в каждом перебрать все объекты. Если количество кварталов взять за M, количество объектов – за N, то сложность решения по времени O(2*M*N), сложность по памяти – O(M*(N+1)).
Код решения с тестами: https://github.com/sbzenenko/NetDeveloper/tree/main/ApartmentFinderSolution
PS: есть ещё нахождение максимума по N и минимума по M, которые сами по себе добавляют O(logM) и O(logN) по времени, но их можно находить параллельно с обратным прохождением массива.
Источник: https://youtu.be/rw4s4M3hFfs
Ответ на задачу про поиск квартиры.
Создадим двумерный массив для хранения расстояний. В строках будут кварталы, в столбцах объекты. При этом, если объект присутствует в квартале, отметим соответствующее расстояние как 0, если нет, для начала отметим его недостижимо большим значением, например,
999999
(ниже буду использовать *
). Таким образом, для примера из задачи:[Первый квартал будет
{{"gym",false},{"school",false},{"store",true}},
{{"gym",true },{"school",false},{"store",false}},
{{"gym",true },{"school",false},{"store",true}},
{{"gym",false },{"school",false},{"store",false}},
{{"gym",false },{"school",true},{"store",true}}
]
1: * * 0Теперь проходим вдоль массива кварталов. Если соответствующий объект есть, заполняем ячейку нулём, в противном случае заполняем её значением на 1 больше, чем в предыдущем квартале. Например, во втором квартале объект
"store"
будет иметь значение 1. Большие значения нас пока не интересуют, там будет значение <очень много>+1
(оставим их как *
). Тогда второй квартал будет:2: 0 * 1И так далее:
3: 0 * 0Теперь проходим массив кварталов обратно. На этом этапе:
4: 1 * 1
5: 2 0 0
1. Задаём значение расстояния как минимальное между существующим значением и значением на 1 больше, чем в предыдущем квартале. То есть, если, проходя в одну сторону, мы получили расстояние до объекта в 3 квартала, но он находится в следующем квартале, то, проходя в обратную сторону, мы зададим минимальное расстояние между 3 и 1 – 1. Аналогичным образом мы заменим все большие значение, обозначенные
*
. 2. Кроме того, рассчитав все расстояния в квартале, считаем максимальное из них.
5: 2 0 0 (макс: 2)И, наконец, из максимальных значений выбираем наименьшее – 1 в 4м квартале.
4: 1 1 1 (макс: 1)
3: 0 2 0 (макс: 2)
2: 0 3 1 (макс: 3)
1: 1 4 0 (макс: 4)
Таким образом, нам нужно дважды пройти массив кварталов, в каждом перебрать все объекты. Если количество кварталов взять за M, количество объектов – за N, то сложность решения по времени O(2*M*N), сложность по памяти – O(M*(N+1)).
Код решения с тестами: https://github.com/sbzenenko/NetDeveloper/tree/main/ApartmentFinderSolution
PS: есть ещё нахождение максимума по N и минимума по M, которые сами по себе добавляют O(logM) и O(logN) по времени, но их можно находить параллельно с обратным прохождением массива.
Источник: https://youtu.be/rw4s4M3hFfs
День семьсот семьдесят первый. #ЧтоНовенького
Что Нового в EF Core 6 Preview 1
Ниже описаны некоторые из основных нововведений в предварительной версии EF Core 6.
1. Атрибут Unicode
Строковое свойство теперь можно сопоставить со столбцом, не поддерживающим Юникод:
2. Атрибут Precision
Теперь можно задать точность поля базы данных, указав количество цифр всего и после запятой, не используя непосредственно тип данных, поддерживаемый СУБД:
Атрибут позволяет определять класс конфигурации сущности, позволяя вынести конфигурацию в отдельный класс, а не помещать её всю в
4. EF.Functions.Random
5. Проверка на null обязательных полей в in-memory базе
In-memory база данных теперь будет выбрасывать исключение при попытке сохранить
Эта проверка может быть отключена при необходимости:
Что Нового в EF Core 6 Preview 1
Ниже описаны некоторые из основных нововведений в предварительной версии EF Core 6.
1. Атрибут Unicode
Строковое свойство теперь можно сопоставить со столбцом, не поддерживающим Юникод:
[Unicode(false)]Поскольку номер ISBN не может содержать не-юникод символы, атрибут сообщит СУБД, что можно использовать не-юникод строку. Например, в SQL Server будет использован varchar вместо
public string Isbn { get; set; }
nvarchar
.2. Атрибут Precision
Теперь можно задать точность поля базы данных, указав количество цифр всего и после запятой, не используя непосредственно тип данных, поддерживаемый СУБД:
[Precision(precision: 10, scale: 2)]3. Атрибут EntityTypeConfiguration
public decimal Price { get; set; }
Атрибут позволяет определять класс конфигурации сущности, позволяя вынести конфигурацию в отдельный класс, а не помещать её всю в
OnModelCreating
.[EntityTypeConfiguration(typeof(BookConfiguration))]При этом класс конфигурации должен реализовывать
public class Book {…}
IEntityTypeConfiguration<T>
:public class BookConfiguration :ПРИМЕЧАНИЕ. Типы, помеченные атрибутом
IEntityTypeConfiguration<Book> {…}
EntityTypeConfiguration
не будут автоматически обнаруживаться в сборке. Типы сущностей должны быть явно добавлены в контекст EF.4. EF.Functions.Random
EF.Functions.Random
соответствует функции СУБД, возвращающей псевдо-случайное число от 0 до 1. Реализации уже готовы для SQL Server, SQLite, и Cosmos.5. Проверка на null обязательных полей в in-memory базе
In-memory база данных теперь будет выбрасывать исключение при попытке сохранить
null
в свойстве, помеченном, как обязательное (например, атрибутом Required
).Эта проверка может быть отключена при необходимости:
….UseInMemoryDatabase("…")Источник: https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-6-0-preview-1/
.EnableNullabilityCheck(false);
День семьсот семьдесят второй. #ЗаметкиНаПолях
Автоматическая Жадная Загрузка Навигационных Свойств в EF Core
Обычно при загрузке навигационных свойств в EF Core вы вынуждены использовать метод
Например, допустим, что у нас есть есть два класса: контакт и его email адреса.
Но что, если мы уверены, что каждый раз, когда мы загружаем контакты, нам сразу нужны их email адреса? Мы уверены, что никогда не будем использовать контакты без email адресов. Часто это характерно для навигационных свойств один-к-одному. Но даже в этом примере, возможно, везде, где мы показываем контакт, нам также нужно показать и его email’ы, поскольку они являются неотъемлемой частью модели.
Настройка AutoInclude
До EF Core 5 у вас действительно не было выбора, кроме как постоянно использовать
Вот и всё. Теперь каждый раз при получении данных
Игнорирование AutoInclude
Конечно, бывают случаи, когда вы настроили
Источник: https://dotnetcoretutorials.com/2021/03/07/eager-load-navigation-properties-by-default-in-ef-core/
Автоматическая Жадная Загрузка Навигационных Свойств в EF Core
Обычно при загрузке навигационных свойств в EF Core вы вынуждены использовать метод
Include
, чтобы указать, какие навигационные свойства нужно вернуть в запрос. Это очень хорошая практика явно указывать, какие данные вам на самом деле нужны.Например, допустим, что у нас есть есть два класса: контакт и его email адреса.
class Contact {При использовании подхода Code First это навигационное свойство будет без проблем обработано на основе соглашений. При запросе контактов, если бы мы хотим сразу получить и
public int Id { get; set; }
public string Name { get; set; }
public ICollection ContactEmails { get; set; }
}
class ContactEmail {
public int ContactId { get; set; }
public Contact Contact { get; set; }
public string Email { get; set; }
}
ContactEmails
, нам пришлось бы написать что-то вроде этого:_context.Contact.Include(x => x.ContactEmails)Это называется жадной загрузкой, потому что мы с сразу загружаем email адреса контактов, например, чтобы вернуть их пользователю или использовать где-нибудь еще в нашем коде.
.FirstOrDefault(x => x.Id == myContactId);
Но что, если мы уверены, что каждый раз, когда мы загружаем контакты, нам сразу нужны их email адреса? Мы уверены, что никогда не будем использовать контакты без email адресов. Часто это характерно для навигационных свойств один-к-одному. Но даже в этом примере, возможно, везде, где мы показываем контакт, нам также нужно показать и его email’ы, поскольку они являются неотъемлемой частью модели.
Настройка AutoInclude
До EF Core 5 у вас действительно не было выбора, кроме как постоянно использовать
Include
. Однако сейчас ситуация поменялась, появилась функция AutoInclude
:builder.Navigation(x => x.ContactEmails).AutoInclude();Строитель навигации используется довольно редко, поэтому не все знают о его возможностях. И стоит упомянуть, что
AutoInclude()
нельзя использовать на конфигурациях вроде HasOne()
или HasMany()
, он должен быть настроен обособленно, как в примере выше.Вот и всё. Теперь каждый раз при получении данных
Contacts
их свойство ContactEmails
будет заполнено без использования Include
.Игнорирование AutoInclude
Конечно, бывают случаи, когда вы настроили
AutoInclude
, а затем вам нужно написать запрос, не включающий навигационное свойство. К счастью, для этого есть хорошее расширение IQueryable
:_context.Contact.IgnoreAutoIncludes()Так мы можем отписаться от получения навигационного свойства, и не запрашивать из базы больше данных, чем нам нужно.
.FirstOrDefault(x => x.Id == myContactId);
Источник: https://dotnetcoretutorials.com/2021/03/07/eager-load-navigation-properties-by-default-in-ef-core/
День семьсот семьдесят третий. #ЧтоНовенького
Прекращение Поддержки .NET Core 2.1
Поддержка .NET Core 2.1 будет прекращена 21 августа 2021 года. После этой даты Microsoft прекратит обновления (включая исправления безопасности) и поддержку этой версии. Необходимо обновить вашу версию .NET Core до поддерживаемой (.NET Core 3.1 или .NET 5.0) до этой даты.
Когда поддержка .NET Core 2.1 прекратится, приложения, использующие эту версию, продолжат работу. При этом обновления безопасности для .NET Core 2.1 начиная с сентября 2021 года выпускаться не будут, в отличие от .NET Core 3.1 и .NET 5.0. То есть .NET Core 2.1 может стать потенциально небезопасной средой.
Обновление приложений
Если ваше приложение использует NET Core 2.1, Microsoft настоятельно рекомендует перенести его на поддерживаемую версию - .NET 3.1 или более позднюю, которые можно скачать с веб-сайта .NET.
Обновление до .NET Core 3.1
Откройте файл проекта (файл
Измените значение целевой платформы с netcoreapp2.1 на netcoreapp3.1. Целевая платформа определяется элементом
Например, измените
Источник: https://devblogs.microsoft.com/dotnet/net-core-2-1-will-reach-end-of-support-on-august-21-2021/
Прекращение Поддержки .NET Core 2.1
Поддержка .NET Core 2.1 будет прекращена 21 августа 2021 года. После этой даты Microsoft прекратит обновления (включая исправления безопасности) и поддержку этой версии. Необходимо обновить вашу версию .NET Core до поддерживаемой (.NET Core 3.1 или .NET 5.0) до этой даты.
Когда поддержка .NET Core 2.1 прекратится, приложения, использующие эту версию, продолжат работу. При этом обновления безопасности для .NET Core 2.1 начиная с сентября 2021 года выпускаться не будут, в отличие от .NET Core 3.1 и .NET 5.0. То есть .NET Core 2.1 может стать потенциально небезопасной средой.
Обновление приложений
Если ваше приложение использует NET Core 2.1, Microsoft настоятельно рекомендует перенести его на поддерживаемую версию - .NET 3.1 или более позднюю, которые можно скачать с веб-сайта .NET.
Обновление до .NET Core 3.1
Откройте файл проекта (файл
*.csproj
, *.vbproj
или *.fsproj
).Измените значение целевой платформы с netcoreapp2.1 на netcoreapp3.1. Целевая платформа определяется элементом
<TargetFramework>
или <TargetFrameworks>
.Например, измените
<TargetFramework>netcoreapp2.1</TargetFramework>На
<TargetFramework>netcoreapp3.1</TargetFramework>.Проверить установленные на компьютере версии .NET можно, выполнив команду:
dotnet --list-runtimesЕсли вы используете Visual Studio 2017 15.9, то у вас также может быть установлен .NET Core 2.1 в качестве обязательного компонента (см. рисунок ниже). Начиная с обновления 15.9.34 в марте 2021 года, компонент .NET Core 2.1 в Visual Studio будет изменен с обязательного на рекомендуемый. Когда поддержка .NET Core 2.1 прекратится, Visual Studio 2017 15.9 будет обновлена и .NET Core 2.1 станет необязательным. То есть различные рабочие нагрузки (Workload) в Visual Studio можно будет установить без установки .NET Core 2.1. При этом существующие установки не будут затронуты. Рабочие нагрузки и компоненты останутся установленными до тех пор, пока не будут явно удалены в установщике Visual Studio. Хотя у вас сохранится возможность установить компонент .NET Core 2.1, настоятельно рекомендуется использовать .NET Core 3.1 или .NET 5.0 с Visual Studio 2019 для создания приложений.
Источник: https://devblogs.microsoft.com/dotnet/net-core-2-1-will-reach-end-of-support-on-august-21-2021/
День семьсот семьдесят четвёртый. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
80. Проверяйте Требуемое, а не Случайное Поведение
Распространённая проблема тестирования - предположение, что реализация делает именно то, на что вы хотите проверить. На первый взгляд, это скорее хорошо, чем плохо. Однако проблема становится очевидной, если перефразировать это предложение: распространённая ошибка при тестировании заключается в привязке тестов к особенностям реализации, когда эти особенности являются случайными и не имеют отношения к желаемой функциональности.
Когда тесты жёстко привязаны к случайным особенностям реализации, изменения в реализации, которые фактически совместимы с требуемым поведением, могут привести к сбою тестов, что приводит к ложным выводам. Программисты обычно реагируют на это либо переписыванием теста, либо переписыванием кода. Предположение, что провал теста действительно свидетельствует об ошибке, часто является следствием страха, неуверенности или сомнений. Вследствие этого случайное поведение кода незаметно перерастает в требуемое поведение. Переписывая тест, программисты либо переориентируют его на требуемое поведение (что хорошо), либо просто подгоняют его под новую реализацию (что плохо). Тесты должны быть достаточно точными, чтобы ловить ошибки в реализации, но они также должны быть аккуратными, чтобы отражать требуемое поведение.
Например, для метода
- он отрицательный, если экземпляр класса стоит по порядку раньше, чем объект, переданный в аргументе метода,
- он положительный, если экземпляр класса стоит позже,
- он равен нулю если объекты считаются равными.
Этот стиль сравнения используется во многих API, включая компаратор для функций сортировки. И хотя конкретные значения
Аналогичная проблема возникает с тестами, которые проверяют количество пробелов, точное написание слов и другие аспекты форматирования и представления текста, которые в реальности являются случайными. Кроме случаев, когда вы пишете генератор XML или JSON, который предлагает настраиваемое форматирование, количество пробелов не должно иметь значения для результата. Точно так же проверка фиксированного расположения кнопок, меток и других элементов управления пользовательского интерфейса уменьшает гибкость приложения и возможность изменения и уточнения этих случайных элементов в будущем. Незначительные изменения в реализации и несущественные изменения в форматировании внезапно становятся нарушителями сборки.
Чрезмерно определённые тесты часто являются проблемой при использовании метода «белого ящика» в модульном тестировании. Тесты методом «белого ящика» используют структуру кода для определения необходимых тестовых случаев. Типичный отказ при таком тестировании происходит, когда тесты проверяют в буквальном смысле, что код делает именно то, что написано в коде. Простое повторение того, что уже очевидно из кода, не добавляет ценности тесту и ведёт к ложному чувству прогресса и безопасности.
Чтобы тесты были эффективными, они должны проверять договорные обязательства, а не реализацию. Необходимо представлять тестируемые модули в виде чёрного ящика, и тестировать реализацию контракта интерфейса. Поэтому всегда проверяйте, согласуется ли тестируемое поведение с требуемым поведением.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Kelvin Henney
97 Вещей, Которые Должен Знать Каждый Программист
80. Проверяйте Требуемое, а не Случайное Поведение
Распространённая проблема тестирования - предположение, что реализация делает именно то, на что вы хотите проверить. На первый взгляд, это скорее хорошо, чем плохо. Однако проблема становится очевидной, если перефразировать это предложение: распространённая ошибка при тестировании заключается в привязке тестов к особенностям реализации, когда эти особенности являются случайными и не имеют отношения к желаемой функциональности.
Когда тесты жёстко привязаны к случайным особенностям реализации, изменения в реализации, которые фактически совместимы с требуемым поведением, могут привести к сбою тестов, что приводит к ложным выводам. Программисты обычно реагируют на это либо переписыванием теста, либо переписыванием кода. Предположение, что провал теста действительно свидетельствует об ошибке, часто является следствием страха, неуверенности или сомнений. Вследствие этого случайное поведение кода незаметно перерастает в требуемое поведение. Переписывая тест, программисты либо переориентируют его на требуемое поведение (что хорошо), либо просто подгоняют его под новую реализацию (что плохо). Тесты должны быть достаточно точными, чтобы ловить ошибки в реализации, но они также должны быть аккуратными, чтобы отражать требуемое поведение.
Например, для метода
CompareTo(object obj)
интерфейса IComparable
, требования к результату заключаются в том, что:- он отрицательный, если экземпляр класса стоит по порядку раньше, чем объект, переданный в аргументе метода,
- он положительный, если экземпляр класса стоит позже,
- он равен нулю если объекты считаются равными.
Этот стиль сравнения используется во многих API, включая компаратор для функций сортировки. И хотя конкретные значения
–1
и +1
обычно используются в реализациях для обозначения отрицательного и положительного результатов, соответственно, программисты часто ошибочно предполагают, что эти значения и представляют фактическое требование, и, следовательно, пишут тесты, которые публично подтверждают это предположение.Аналогичная проблема возникает с тестами, которые проверяют количество пробелов, точное написание слов и другие аспекты форматирования и представления текста, которые в реальности являются случайными. Кроме случаев, когда вы пишете генератор XML или JSON, который предлагает настраиваемое форматирование, количество пробелов не должно иметь значения для результата. Точно так же проверка фиксированного расположения кнопок, меток и других элементов управления пользовательского интерфейса уменьшает гибкость приложения и возможность изменения и уточнения этих случайных элементов в будущем. Незначительные изменения в реализации и несущественные изменения в форматировании внезапно становятся нарушителями сборки.
Чрезмерно определённые тесты часто являются проблемой при использовании метода «белого ящика» в модульном тестировании. Тесты методом «белого ящика» используют структуру кода для определения необходимых тестовых случаев. Типичный отказ при таком тестировании происходит, когда тесты проверяют в буквальном смысле, что код делает именно то, что написано в коде. Простое повторение того, что уже очевидно из кода, не добавляет ценности тесту и ведёт к ложному чувству прогресса и безопасности.
Чтобы тесты были эффективными, они должны проверять договорные обязательства, а не реализацию. Необходимо представлять тестируемые модули в виде чёрного ящика, и тестировать реализацию контракта интерфейса. Поэтому всегда проверяйте, согласуется ли тестируемое поведение с требуемым поведением.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Kelvin Henney
День семьсот семьдесят пятый. #ЧтоНовенького
Новое Динамическое Инструментальное Профилирование для .NET
С выпуском Visual Studio версии 16.9 инструменты профилирования в Visual Studio стали ещё лучше. Новый инструмент динамического инструментального профилирования показывает точное количество вызовов ваших функций и работает быстрее, чем его предшественники. Он также поддерживает инструментарий .NET Core без использования файлов PDB.
Вы можете получить доступ к инструменту динамического профилирования, запустив профилировщик производительности для проекта .NET в Visual Studio (Debug > Performance Profiler или Alt+F2). В открывшейся вкладке отметьте флажок рядом с блоком Instrumentation. См. видео.
В профилировании существует два метода сбора данных: instrumentation (инструментальный) и sampling (метод выборки). В инструментальном профилировании каждый вызов функции в вашем приложении аннотируется, поэтому при вызове метод добавляется в трассировку вместе с информацией о вызывающем коде. При методе выборки текущий стек выполнения извлекается из ЦП в определённые интервалы времени, а затем каждый такой «кадр» добавляется к трассировке.
Ценность выборки заключается в меньшем объёме «прослушки» и, следовательно, она с большей вероятностью будет статистически репрезентативной для приложения, работающего в производственной среде. Ценность инструментального профилирования в том, что вы можете получить точное количество вызовов на основе того, сколько раз были вызваны ваши функции. Это даёт вам гораздо более подробную информацию, чем в методе выборки, не искажённую затратами на извлечение стека. Например, при методе выборки функции, которые выполняются быстро, но часто вызываются, будут отображаться чаще, чем в реальном мире.
Новый сценарий динамического инструментального профилирования даёт ещё несколько преимуществ.
Во-первых, заметное улучшение скорости работы инструмента профилирования из-за отказа от использования VSInstr.
Во-вторых, теперь поддерживаются проекты .NET Core без PDB. Раньше, чтобы использовать инструментарий профилирования, сборку приходилось модифицировать для создания полноценных PDB файлов. Теперь вы можете запускать свои проекты «как есть», не выполняя никаких дополнительных действий.
Справка: PDB – это файлы базы данных программы, также называются файлами символов, которые используются для сопоставления идентификаторов и инструкций в исходном коде вашего проекта с соответствующими идентификаторами и инструкциями в скомпилированных приложениях. С помощью этих файлов отладчик связывается с исходным кодом, что позволяет выполнять его отладку.
И наконец, обновлённый инструмент профилирования не требует изменения файлов сборки. Это означает, что можно проводить инструментальное профилирование производственного кода, не боясь случайно нарушить цифровые подписи сборок.
Источник: https://devblogs.microsoft.com/visualstudio/new-dynamic-instrumentation-profiling/
Новое Динамическое Инструментальное Профилирование для .NET
С выпуском Visual Studio версии 16.9 инструменты профилирования в Visual Studio стали ещё лучше. Новый инструмент динамического инструментального профилирования показывает точное количество вызовов ваших функций и работает быстрее, чем его предшественники. Он также поддерживает инструментарий .NET Core без использования файлов PDB.
Вы можете получить доступ к инструменту динамического профилирования, запустив профилировщик производительности для проекта .NET в Visual Studio (Debug > Performance Profiler или Alt+F2). В открывшейся вкладке отметьте флажок рядом с блоком Instrumentation. См. видео.
В профилировании существует два метода сбора данных: instrumentation (инструментальный) и sampling (метод выборки). В инструментальном профилировании каждый вызов функции в вашем приложении аннотируется, поэтому при вызове метод добавляется в трассировку вместе с информацией о вызывающем коде. При методе выборки текущий стек выполнения извлекается из ЦП в определённые интервалы времени, а затем каждый такой «кадр» добавляется к трассировке.
Ценность выборки заключается в меньшем объёме «прослушки» и, следовательно, она с большей вероятностью будет статистически репрезентативной для приложения, работающего в производственной среде. Ценность инструментального профилирования в том, что вы можете получить точное количество вызовов на основе того, сколько раз были вызваны ваши функции. Это даёт вам гораздо более подробную информацию, чем в методе выборки, не искажённую затратами на извлечение стека. Например, при методе выборки функции, которые выполняются быстро, но часто вызываются, будут отображаться чаще, чем в реальном мире.
Новый сценарий динамического инструментального профилирования даёт ещё несколько преимуществ.
Во-первых, заметное улучшение скорости работы инструмента профилирования из-за отказа от использования VSInstr.
Во-вторых, теперь поддерживаются проекты .NET Core без PDB. Раньше, чтобы использовать инструментарий профилирования, сборку приходилось модифицировать для создания полноценных PDB файлов. Теперь вы можете запускать свои проекты «как есть», не выполняя никаких дополнительных действий.
Справка: PDB – это файлы базы данных программы, также называются файлами символов, которые используются для сопоставления идентификаторов и инструкций в исходном коде вашего проекта с соответствующими идентификаторами и инструкциями в скомпилированных приложениях. С помощью этих файлов отладчик связывается с исходным кодом, что позволяет выполнять его отладку.
И наконец, обновлённый инструмент профилирования не требует изменения файлов сборки. Это означает, что можно проводить инструментальное профилирование производственного кода, не боясь случайно нарушить цифровые подписи сборок.
Источник: https://devblogs.microsoft.com/visualstudio/new-dynamic-instrumentation-profiling/
День семьсот семьдесят шестой.
Будни программиста
Сегодня будет не совсем про программирование. Сегодня история личной боли (или тупости, вам решать). Я уже писал в нашем чате пару дней назад, что винда предложила под угрозой прекращения поддержки обновиться до версии 20H2. Что в этой версии такого революционного, я так и не понял. Но в выходные потратил 3,5 часа на обновление домашнего ноута. Наивный я думал, что вечером в понедельник быстренько обновлю новенький рабочий ноут, а потом подготовлю статью для канала.
Собственно обновление то действительно прошло быстрее (около часа), зато потом началось сплошное веселье. То, что перестало работать гнездо для наушников (к которому у меня перманентно подключены колонки) или что исчезла панель быстрого доступа слева в проводнике – это мелочи, на которые я даже не обращаю внимания. Старый добрый Майкрософт в своём репертуаре. Это я быстро восстановил.
Гораздо больше радости доставил отвалившийся Microsoft Loopback Adapter, к которому были подключены 2 виртуальные машины VirtualBox (машина для разработки и машина чисто с оракловской базой). Они через этот адаптер ноута по VirtualBox Bridged Adapter были связаны друг с другом.
- Не беда, - подумал я, - сейчас переустановлю Loopback адаптер, и всё ок.
- А вот хрен там, - ответила винда.
Для начала сам Loopback адаптер стал показывать «Undefined network». Я в принципе редко в него лазил, и не представлял, что он должен в нормальном состоянии показывать. Всё-таки, он тестовый, может неопределённая сеть для него – это нормально. Однако машины наотрез отказывались соединяться хоть с чем-нибудь, поэтому пришлось гуглить. Нашёл вот такое решение. Оооо… ручная правка реестра, как я по ней скучал!
Сеть появилась, оракловая машина заработала, как ни в чём не бывало, и стала пинговать машину для разработки (хотя мне этого и не надо), а вот вторая наотрез отказывалась видеть оракловую. Все настройки адаптеров виртуалок сохранились, там ничего не менялось, но соединяться машины отказывались наотрез.
После трёх часов тыкания в разные настройки машин, хоста и VirtualBox, ближе к 10 вечера, решил написать начальнику (благо, у него в штатах день только начинался). У него ровно те же виртуалки и почти такой же рабочий ноут. Скопировали все его настройки до запятой – нифига. Стали пробовать пинговать по IPv6 – нифига. Тут, кстати, стоит оговориться, что ораклу для подключения нужна сеть 10.x.x.x, поэтому все адаптеры были настроены на статические IPv4 и отдельную подсеть только для этих двух виртуалок. У виртуалки для разработки есть отдельное подключение для интернета, оракловой виртуалке интернет не нужен, поэтому у неё только одно подключение по мосту к другой виртуалке.
Всё, чего смогли добиться – что виртуалка для разработки стала пинговать основную машину. При этом оракловая виртуалка отказывалась её пинговать, зато прекрасно соединялась с виртуалкой для разработки.
Стали гуглить добавление статических маршрутов. Ни один из нас не сисадмин, так что из этого тоже ничего не вышло. Близилась полночь… Начал я в этом ковыряться в начале 7го.
Вот теперь вопрос, ибо мне самому интересно. Это я настолько туп (хотя, повторюсь, не сисадмин совсем)? Может вы сразу поняли, в чём было дело?
Напомню вкратце:
Рабочий ноут, в нём 2 виртуалки VirtualBox, соединённые по Bridged Adapter между собой, используя Microsoft Loopback Adapter ноута. До обновления винды на ноуте всё работало, потом перестало. Соединения в виртуалках настроены на статические IP в сети 10.x.x.x. Одна виртуалка с базой данных видит вторую, но не видит ноут. Вторая видит ноут, но не видит виртуалку с базой (а именно это соединение и требуется).
UPD: Видимо, всё же я тупой, т.к. в комментариях уже через 15 минут предложили правильный вариант. Да, чудил файрвол в оракловой виртуалке. Каким-то макаром после всех манипуляций с Loopback адаптером на ноуте, сеть в оракловой виртуалке из приватной стала публичной. А для публичных сетей файрвол блокировал все попытки внешних подключений. Вот, кстати, вдруг кому пригодится, как изменить тип сети обратно на приватную.
Будни программиста
Сегодня будет не совсем про программирование. Сегодня история личной боли (или тупости, вам решать). Я уже писал в нашем чате пару дней назад, что винда предложила под угрозой прекращения поддержки обновиться до версии 20H2. Что в этой версии такого революционного, я так и не понял. Но в выходные потратил 3,5 часа на обновление домашнего ноута. Наивный я думал, что вечером в понедельник быстренько обновлю новенький рабочий ноут, а потом подготовлю статью для канала.
Собственно обновление то действительно прошло быстрее (около часа), зато потом началось сплошное веселье. То, что перестало работать гнездо для наушников (к которому у меня перманентно подключены колонки) или что исчезла панель быстрого доступа слева в проводнике – это мелочи, на которые я даже не обращаю внимания. Старый добрый Майкрософт в своём репертуаре. Это я быстро восстановил.
Гораздо больше радости доставил отвалившийся Microsoft Loopback Adapter, к которому были подключены 2 виртуальные машины VirtualBox (машина для разработки и машина чисто с оракловской базой). Они через этот адаптер ноута по VirtualBox Bridged Adapter были связаны друг с другом.
- Не беда, - подумал я, - сейчас переустановлю Loopback адаптер, и всё ок.
- А вот хрен там, - ответила винда.
Для начала сам Loopback адаптер стал показывать «Undefined network». Я в принципе редко в него лазил, и не представлял, что он должен в нормальном состоянии показывать. Всё-таки, он тестовый, может неопределённая сеть для него – это нормально. Однако машины наотрез отказывались соединяться хоть с чем-нибудь, поэтому пришлось гуглить. Нашёл вот такое решение. Оооо… ручная правка реестра, как я по ней скучал!
Сеть появилась, оракловая машина заработала, как ни в чём не бывало, и стала пинговать машину для разработки (хотя мне этого и не надо), а вот вторая наотрез отказывалась видеть оракловую. Все настройки адаптеров виртуалок сохранились, там ничего не менялось, но соединяться машины отказывались наотрез.
После трёх часов тыкания в разные настройки машин, хоста и VirtualBox, ближе к 10 вечера, решил написать начальнику (благо, у него в штатах день только начинался). У него ровно те же виртуалки и почти такой же рабочий ноут. Скопировали все его настройки до запятой – нифига. Стали пробовать пинговать по IPv6 – нифига. Тут, кстати, стоит оговориться, что ораклу для подключения нужна сеть 10.x.x.x, поэтому все адаптеры были настроены на статические IPv4 и отдельную подсеть только для этих двух виртуалок. У виртуалки для разработки есть отдельное подключение для интернета, оракловой виртуалке интернет не нужен, поэтому у неё только одно подключение по мосту к другой виртуалке.
Всё, чего смогли добиться – что виртуалка для разработки стала пинговать основную машину. При этом оракловая виртуалка отказывалась её пинговать, зато прекрасно соединялась с виртуалкой для разработки.
Стали гуглить добавление статических маршрутов. Ни один из нас не сисадмин, так что из этого тоже ничего не вышло. Близилась полночь… Начал я в этом ковыряться в начале 7го.
Вот теперь вопрос, ибо мне самому интересно. Это я настолько туп (хотя, повторюсь, не сисадмин совсем)? Может вы сразу поняли, в чём было дело?
Напомню вкратце:
Рабочий ноут, в нём 2 виртуалки VirtualBox, соединённые по Bridged Adapter между собой, используя Microsoft Loopback Adapter ноута. До обновления винды на ноуте всё работало, потом перестало. Соединения в виртуалках настроены на статические IP в сети 10.x.x.x. Одна виртуалка с базой данных видит вторую, но не видит ноут. Вторая видит ноут, но не видит виртуалку с базой (а именно это соединение и требуется).
UPD: Видимо, всё же я тупой, т.к. в комментариях уже через 15 минут предложили правильный вариант. Да, чудил файрвол в оракловой виртуалке. Каким-то макаром после всех манипуляций с Loopback адаптером на ноуте, сеть в оракловой виртуалке из приватной стала публичной. А для публичных сетей файрвол блокировал все попытки внешних подключений. Вот, кстати, вдруг кому пригодится, как изменить тип сети обратно на приватную.
День семьсот семьдесят седьмой. #юмор
Да, очень похоже на правду.
А ещё вдогонку вам на сегодня свежее видео от ExtremeCode на смежную тему)))
Да, очень похоже на правду.
А ещё вдогонку вам на сегодня свежее видео от ExtremeCode на смежную тему)))