День четыреста шестьдесят четвёртый.
Примеры из Реальной Жизни
Продолжил читать книгу Адама Фримена «ASP.NET Core MVC 2», и вспомнил ещё один, и наверное самый главный её недостаток (хотя он присутствует во многих других источниках) - это отсутствие примеров из реальной жизни. У меня нет педагогического образования, как и опыта обучения кого-либо (кроме двух дочерей младших школьниц). Но по своему личному опыту изучения материала я отметил 3 необходимых условия изучения той или иной темы (чтобы «пройти тему не мимо, а пройти в смысле запомнить», как говорили в моей школе):
1. Выделить и запомнить главную мысль. Это должно быть процентов 5-10 от объёма. Больше запомнить просто невозможно, да и не нужно. В принципе, это как раз то, чем я занимаюсь на этом канале. 20-30 страниц книги сжимаю до 1-1,5 страниц, чтобы влезло в 1 пост. Хотя, иногда информации столько, что приходится разбивать на несколько постов.
2. Поместить знания в контекст. Представьте, что весь курс (допустим, ASP.NET MVC) – это большой паззл. Каждый отдельный элемент: настройки приложения, маршрутизация, Razor, привязка модели и т.п. – это кусочки паззла. Чтобы изучить тему, недостаточно просто выучить весь набор элементов. Эти знания будут существовать в вакууме, а поэтому быстро забудутся. Нужно, чтобы сложилась цельная картина, – положить каждый кусочек в нужное место, понять, как он связан с остальными, и тогда он не «выпадет» и не «потеряется».
3. Рассмотреть реальный пример использования. Каждый кусочек паззла должен иметь смысл и назначение. Считайте, что это клей, которым вы приклеите кусочек к подложке, чтобы он не отваливался. Если ты не знаешь, для чего тебе конкретное знание, рано или поздно оно забудется, т.к. потеряет смысл. На этом я пытаюсь делать акцент в моих постах: «ЗАЧЕМ мне это знание. В каких реальных обстоятельствах оно мне пригодится.» Даже если приведённый в источнике пример не подходит для вашего случая, его легко подогнать, слегка изменив пример, а не придумывая его с нуля.
Несколько примеров:
1. Собственно из вышеупомянутой книги. Тема tag-хелперов (или, как они в книге называются «вспомогательных функций дескрипторов»). Почти 20 страниц с описанием, как создать собственный tag-хелпер. И перед этим описанием фраза: «Этот пример бесполезный, мы просто объясняем принцип работы». И это далеко не единичный случай. Наверное, каждый хоть раз встречал подобный пассаж в книгах. Как вариант ещё: «В следующей главе мы объясним, как эти 100500 строчек кода можно сократить до вызова одной стандартной функции». Лично мой мозг, прочитав это, бессознательно делает пометку, что следующий текст бесполезен и запоминать его не надо.
Поймите правильно, это не всегда плохо. Можно прочитать подробно про алгоритм сортировки, а потом узнать, что в реальной жизни просто используется функция Sort или OrderBy. Но когда объясняется функционал реальных приложений, неужели сложно при подготовке материала придумать хоть один более-менее реальный пример из практики?
2. Явная реализация интерфейса (Рихтер). Неплохое объяснение и даже пример, но варианты реального применения из этого примера не очевидны. А вот гораздо более полезный пример.
3. Недавно я писал про новую функцию в .NET 5 - Генераторы Кода. После этого в наш чат кинули ссылку на статью, где автор описал использование генератора кода в nuGet пакете для создания строителя экземпляра. Если коротко, то, подключив этот пакет, класс (например,
Для каждой изучаемой темы ищите примеры использования в ваших приложениях. Это очень помогает её пониманию и запоминанию.
Примеры из Реальной Жизни
Продолжил читать книгу Адама Фримена «ASP.NET Core MVC 2», и вспомнил ещё один, и наверное самый главный её недостаток (хотя он присутствует во многих других источниках) - это отсутствие примеров из реальной жизни. У меня нет педагогического образования, как и опыта обучения кого-либо (кроме двух дочерей младших школьниц). Но по своему личному опыту изучения материала я отметил 3 необходимых условия изучения той или иной темы (чтобы «пройти тему не мимо, а пройти в смысле запомнить», как говорили в моей школе):
1. Выделить и запомнить главную мысль. Это должно быть процентов 5-10 от объёма. Больше запомнить просто невозможно, да и не нужно. В принципе, это как раз то, чем я занимаюсь на этом канале. 20-30 страниц книги сжимаю до 1-1,5 страниц, чтобы влезло в 1 пост. Хотя, иногда информации столько, что приходится разбивать на несколько постов.
2. Поместить знания в контекст. Представьте, что весь курс (допустим, ASP.NET MVC) – это большой паззл. Каждый отдельный элемент: настройки приложения, маршрутизация, Razor, привязка модели и т.п. – это кусочки паззла. Чтобы изучить тему, недостаточно просто выучить весь набор элементов. Эти знания будут существовать в вакууме, а поэтому быстро забудутся. Нужно, чтобы сложилась цельная картина, – положить каждый кусочек в нужное место, понять, как он связан с остальными, и тогда он не «выпадет» и не «потеряется».
3. Рассмотреть реальный пример использования. Каждый кусочек паззла должен иметь смысл и назначение. Считайте, что это клей, которым вы приклеите кусочек к подложке, чтобы он не отваливался. Если ты не знаешь, для чего тебе конкретное знание, рано или поздно оно забудется, т.к. потеряет смысл. На этом я пытаюсь делать акцент в моих постах: «ЗАЧЕМ мне это знание. В каких реальных обстоятельствах оно мне пригодится.» Даже если приведённый в источнике пример не подходит для вашего случая, его легко подогнать, слегка изменив пример, а не придумывая его с нуля.
Несколько примеров:
1. Собственно из вышеупомянутой книги. Тема tag-хелперов (или, как они в книге называются «вспомогательных функций дескрипторов»). Почти 20 страниц с описанием, как создать собственный tag-хелпер. И перед этим описанием фраза: «Этот пример бесполезный, мы просто объясняем принцип работы». И это далеко не единичный случай. Наверное, каждый хоть раз встречал подобный пассаж в книгах. Как вариант ещё: «В следующей главе мы объясним, как эти 100500 строчек кода можно сократить до вызова одной стандартной функции». Лично мой мозг, прочитав это, бессознательно делает пометку, что следующий текст бесполезен и запоминать его не надо.
Поймите правильно, это не всегда плохо. Можно прочитать подробно про алгоритм сортировки, а потом узнать, что в реальной жизни просто используется функция Sort или OrderBy. Но когда объясняется функционал реальных приложений, неужели сложно при подготовке материала придумать хоть один более-менее реальный пример из практики?
2. Явная реализация интерфейса (Рихтер). Неплохое объяснение и даже пример, но варианты реального применения из этого примера не очевидны. А вот гораздо более полезный пример.
3. Недавно я писал про новую функцию в .NET 5 - Генераторы Кода. После этого в наш чат кинули ссылку на статью, где автор описал использование генератора кода в nuGet пакете для создания строителя экземпляра. Если коротко, то, подключив этот пакет, класс (например,
Person
) можно пометить атрибутом GenerateBuilder
, и для него будет сгенерирован код строителя Builder
. Таким образом, не написав ни строчки кода строителя, можно его использовать:var person = Person.BuilderТам же, в чате, у других участников после прочтения этой статьи сразу возникли идеи, как использовать генератор кода в своей практике.
.FirstName("John")
.LastName("Smith")
.BirthDate(1980,3,1)
.Build();
Для каждой изучаемой темы ищите примеры использования в ваших приложениях. Это очень помогает её пониманию и запоминанию.
День четыреста шестьдесят пятый. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по ООП. 20-25.
20. Что такое перегрузка операторов?
Перегрузки операторов - это функции со специальными именами: ключевое слово
Как и любая другая функция, перегруженный оператор имеет тип возвращаемого значения и список параметров. См. также «Советы по перегрузке операторов»
21. Возможно ли, чтобы метод возвращал несколько значений одновременно?
Метод может возвращать несколько значений. Вариантами реализации могут быть:
- Пара ключ-значение
- Структура или класс
- Кортеж
- Коллекции
- Параметры ref или out. См. также «В чем разница между ключевыми словами ref и out?»
22. Что такое константы?
Константы в C# определяется с помощью ключевого слова
23. Что такое Readonly?
Ключевым словом
См. также «В чем разница между константой и полем только для чтения в C#?»
24. Что такое Static?
Ключевое слово
Ключевые особенности:
- Если ключевое слово
- Статические методы могут получить доступ только к статическим членам того же класса.
- Статические свойства используются для получения или установки значения статических полей класса.
- Статический конструктор не может иметь параметров или модификаторов доступа, он по умолчанию открытый.
25. Может ли this использоваться в статическом методе?
Нет, потому что ключевое слово this возвращает ссылку на текущий экземпляр класса, который его содержит. Статические методы (или любые статические члены) не принадлежат конкретному экземпляру. Подробнее…
Источник: https://www.c-sharpcorner.com
Самые часто задаваемые вопросы на собеседовании по ООП. 20-25.
20. Что такое перегрузка операторов?
Перегрузки операторов - это функции со специальными именами: ключевое слово
operator
, за которым следует символ определяемого оператора.Как и любая другая функция, перегруженный оператор имеет тип возвращаемого значения и список параметров. См. также «Советы по перегрузке операторов»
21. Возможно ли, чтобы метод возвращал несколько значений одновременно?
Метод может возвращать несколько значений. Вариантами реализации могут быть:
- Пара ключ-значение
- Структура или класс
- Кортеж
- Коллекции
- Параметры ref или out. См. также «В чем разница между ключевыми словами ref и out?»
22. Что такое константы?
Константы в C# определяется с помощью ключевого слова
const
. Константы известны во время компиляции и не изменяют своего значения во время выполнения. Компилятор записывает значения констант непосредственно в вызывающий код. Следовательно, константы не могут быть изменены без риска нарушения совместимости.23. Что такое Readonly?
Ключевым словом
readonly
в C# помечаются элементы только для чтения. Значение readonly
элементу можно задать при инициализации переменной или в конструкторе экземпляра, но далее его изменять нельзя.См. также «В чем разница между константой и полем только для чтения в C#?»
24. Что такое Static?
Ключевое слово
static
используется для обозначения статического члена. Статические члены являются общими для всех объектов типа и не привязаны к конкретному экземпляру. Ключевое слово static
может использоваться с классами, полями, методами, локальными функциями (C#8+), свойствами, операторами, событиями и конструкторами, но не может использоваться с индексаторами, деструкторами или типами, отличными от классов.Ключевые особенности:
- Если ключевое слово
static
применяется к классу, все члены класса должны быть статическими.- Статические методы могут получить доступ только к статическим членам того же класса.
- Статические свойства используются для получения или установки значения статических полей класса.
- Статический конструктор не может иметь параметров или модификаторов доступа, он по умолчанию открытый.
25. Может ли this использоваться в статическом методе?
Нет, потому что ключевое слово this возвращает ссылку на текущий экземпляр класса, который его содержит. Статические методы (или любые статические члены) не принадлежат конкретному экземпляру. Подробнее…
Источник: https://www.c-sharpcorner.com
👍1
День четыреста шестьдесят шестой. #MoreEffectiveCSharp
10. Избегайте Операторов Приведения в Публичных API
Операторы приведения вводят своего рода взаимозаменяемость между классами. То есть один класс может быть заменён другим. Это может быть преимуществом: объект производного класса может быть заменён объектом его базового класса, как в классическом примере полиморфизма.
Когда вы определяете оператор преобразования для вашего типа, вы сообщаете компилятору, что ваш тип может быть заменён на целевой тип. Эти замены часто приводят к тонким ошибкам, потому что ваш тип, вероятно, не является идеальной заменой целевого типа. Методы, изменяющие состояние целевого типа, не будут отражаться на вашем типе. А если ваш оператор приведения возвращает временный объект, изменения и вовсе будут утеряны.
Рассмотрим объекты круг (
Вместо приведения используйте конструктор, принимающий исходный тип в качестве параметра. Определим в классе
Источник: Bill Wagner “More Effective C#”. – 2nd ed. Глава 11.
10. Избегайте Операторов Приведения в Публичных API
Операторы приведения вводят своего рода взаимозаменяемость между классами. То есть один класс может быть заменён другим. Это может быть преимуществом: объект производного класса может быть заменён объектом его базового класса, как в классическом примере полиморфизма.
Когда вы определяете оператор преобразования для вашего типа, вы сообщаете компилятору, что ваш тип может быть заменён на целевой тип. Эти замены часто приводят к тонким ошибкам, потому что ваш тип, вероятно, не является идеальной заменой целевого типа. Методы, изменяющие состояние целевого типа, не будут отражаться на вашем типе. А если ваш оператор приведения возвращает временный объект, изменения и вовсе будут утеряны.
Рассмотрим объекты круг (
Circle
) и эллипс (Ellipse
), производные от абстрактного класса фигуры (Shape
). Допустим, вы решили сохранить эту иерархию классов, но вам может потребоваться использовать круг вместо эллипса в некоторых случаях (ведь каждый круг является эллипсом), и вы решили реализовать оператор приведения круга к эллипсу:public class Circle : Shape {Оператор неявного приведения будет вызываться всякий раз, когда один тип необходимо преобразовать в другой тип. Оператор явного (explicit) приведения вызывается только когда программист явно использует оператор приведения:
private Point center;
private double radius;
public Circle(Point c, double r) {
center = c;
radius = r;
}
static public implicit operator Ellipse(Circle c) {
return new Ellipse(c.center, c.center, c.radius, c.radius);
}
}
Ellipse e = (Ellipse)circle.Теперь, можно использовать
Circle
в любом месте, где ожидается Ellipse
, и приведение произойдёт автоматически:public static double ComputeArea(Ellipse e)Вот что подразумевалось под взаимозаменяемостью: круг можно использовать вместо эллипса, и всё работает. Однако рассмотрим следующий метод, «сплющивающий» эллипс:
=> e.R1 * e.R2 * Math.PI;
Circle c1 = new Circle(new Point(3.0, 0), 5.0f);
ComputeArea(c1);
public static void Flatten(Ellipse e) {Этот код не сработает. Выполнится неявное приведение, и метод
e.R1 /= 2;
e.R2 *= 2;
}
Circle c = new Circle(new Point(3.0, 0), 5.0);
Flatten(c);
Flatten()
изменит новый временный объект эллипса, который тут же попадёт в мусор. Исходный круг c при этом не изменится.Вместо приведения используйте конструктор, принимающий исходный тип в качестве параметра. Определим в классе
Ellipse
конструктор, принимающий Circle
как параметр и создающий эллипс из круга. Тогда код выше будет выглядеть так:Circle c = new Circle(new Point(3.0, 0), 5.0);Большинство программистов увидят проблему: любые модификации эллипса в методе
Flatten(new Ellipse(c));
Flatten()
теряются. Они исправят проблему, создав новый объект:Circle c = new Circle(new Point(3.0, 0), 5.0);Переменная
Ellipse e = new Ellipse(c);
Flatten(e);
e
будет содержать сплющенный эллипс. Заменив оператор преобразования на конструктор, мы не потеряли никакой функциональности, а только сделали очевидным, что при приведении создаётся новый объект.Источник: Bill Wagner “More Effective C#”. – 2nd ed. Глава 11.
День четыреста шестьдесят седьмой. #DesignPatterns
Принципы SOLID.
4. Принцип разделения интерфейса (ISP)
«Клиенты не должны вынужденно зависеть от методов, которыми не пользуются» (Мартин Р. Принципы, паттерны и практики гибкой разработки. — 2006)
Принцип разделения интерфейса предназначен для получения простого и слабосвязанного кода. Клиенты сервиса должны зависеть лишь от тех методов, которые используют, и не должны знать о существовании не интересующих их частей интерфейса сервиса. Проблема в том, что разработчик сервиса не всегда знает о том, кто и как его будет использовать. Поэтому может потребоваться несколько перегруппировок методов таким образом, чтобы их использование было удобным максимальному числу клиентов.
Принцип ISP является частным случаем принципа наименьшего знания: для получения простого в сопровождении кода каждый класс должен знать минимум информации об окружающем коде - только то, что необходимо для решения его задачи. На практике это значит, что нужно минимизировать число зависимостей класса и стремиться использовать наиболее простые типы зависимостей. Чем больше у класса зависимостей, тем сложнее понять его роль, сложнее тестировать и использовать повторно. Также это увеличивает вероятность поломки класса при изменении зависимостей. Зависимости от простых к сложным:
- примитивные типы;
- структуры и неизменяемые пользовательские типы;
- объекты со стабильным интерфейсом и поведением (поведение которых не зависит от внешнего окружения);
- объекты с изменчивыми интерфейсом и поведением (типы на стыке модулей, или типы, которые работают с внешним окружением: файлами, базами данных, сокетами и т.п.).
Не следует путать принцип разделения интерфейса (ISP) с принципом единственной обязанности (SRP). Если класс или модуль отвечает за выполнение разнородных задач, то он нарушает принцип SRP. Но можем ли мы, глядя на класс или его интерфейс, сказать, что он нарушает он принцип ISP?
Например, класс репозитория, который содержит CRUD-операции. Нарушает ли он ISP? Мы не знаем! Нарушение этого принципа зависит не столько от самого класса, сколько от сценариев его использования. Если в нашей бизнес-модели четко разделяются операции чтения и обновления данных, то наличие одного класса со всеми операциями работы с данными однозначно нарушает ISP. В то же время если приложение содержит множество простых форм, которые 1 к 1 с поставщиками данных, то принцип ISP не нарушается.
Таким образом, следование принципу единственной обязанности приводит к связным (cohesive) классам, что позволяет с меньшими усилиями их понимать и развивать. Следование принципу разделения интерфейсов уменьшает связанность (coupling) между классами и их клиентами, чтобы клиенты использовали более простые зависимости.
Типичные примеры нарушения ISP
- Метод принимает в качестве аргумента производный класс, хотя достаточно использовать базовый.
- У класса два или более ярко выраженных вида клиентов.
- Класс зависит от более сложной зависимости, чем нужно: принимает интерфейс провайдера вместо результатов его работы и т. п.
- Класс зависит от сложного интерфейса, что делает его зависимым от всех типов, используемых в этом интерфейсе.
Лишь по исходному коду класса или его интерфейса мы не можем судить о том, нарушает он принцип разделения интерфейсов или нет. Для этого нужно посмотреть контекст его использования. Если класс используется разными клиентами, это может говорить о слишком большом числе обязанностей, поэтому его нужно упростить. В некоторых случаях у класса может быть одна обязанность, которая рассматривается клиентами с разных точек зрения. Тогда это нужно выразить явно путем реализации двух или более интерфейсов.
Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 20.
Принципы SOLID.
4. Принцип разделения интерфейса (ISP)
«Клиенты не должны вынужденно зависеть от методов, которыми не пользуются» (Мартин Р. Принципы, паттерны и практики гибкой разработки. — 2006)
Принцип разделения интерфейса предназначен для получения простого и слабосвязанного кода. Клиенты сервиса должны зависеть лишь от тех методов, которые используют, и не должны знать о существовании не интересующих их частей интерфейса сервиса. Проблема в том, что разработчик сервиса не всегда знает о том, кто и как его будет использовать. Поэтому может потребоваться несколько перегруппировок методов таким образом, чтобы их использование было удобным максимальному числу клиентов.
Принцип ISP является частным случаем принципа наименьшего знания: для получения простого в сопровождении кода каждый класс должен знать минимум информации об окружающем коде - только то, что необходимо для решения его задачи. На практике это значит, что нужно минимизировать число зависимостей класса и стремиться использовать наиболее простые типы зависимостей. Чем больше у класса зависимостей, тем сложнее понять его роль, сложнее тестировать и использовать повторно. Также это увеличивает вероятность поломки класса при изменении зависимостей. Зависимости от простых к сложным:
- примитивные типы;
- структуры и неизменяемые пользовательские типы;
- объекты со стабильным интерфейсом и поведением (поведение которых не зависит от внешнего окружения);
- объекты с изменчивыми интерфейсом и поведением (типы на стыке модулей, или типы, которые работают с внешним окружением: файлами, базами данных, сокетами и т.п.).
Не следует путать принцип разделения интерфейса (ISP) с принципом единственной обязанности (SRP). Если класс или модуль отвечает за выполнение разнородных задач, то он нарушает принцип SRP. Но можем ли мы, глядя на класс или его интерфейс, сказать, что он нарушает он принцип ISP?
Например, класс репозитория, который содержит CRUD-операции. Нарушает ли он ISP? Мы не знаем! Нарушение этого принципа зависит не столько от самого класса, сколько от сценариев его использования. Если в нашей бизнес-модели четко разделяются операции чтения и обновления данных, то наличие одного класса со всеми операциями работы с данными однозначно нарушает ISP. В то же время если приложение содержит множество простых форм, которые 1 к 1 с поставщиками данных, то принцип ISP не нарушается.
Таким образом, следование принципу единственной обязанности приводит к связным (cohesive) классам, что позволяет с меньшими усилиями их понимать и развивать. Следование принципу разделения интерфейсов уменьшает связанность (coupling) между классами и их клиентами, чтобы клиенты использовали более простые зависимости.
Типичные примеры нарушения ISP
- Метод принимает в качестве аргумента производный класс, хотя достаточно использовать базовый.
- У класса два или более ярко выраженных вида клиентов.
- Класс зависит от более сложной зависимости, чем нужно: принимает интерфейс провайдера вместо результатов его работы и т. п.
- Класс зависит от сложного интерфейса, что делает его зависимым от всех типов, используемых в этом интерфейсе.
Лишь по исходному коду класса или его интерфейса мы не можем судить о том, нарушает он принцип разделения интерфейсов или нет. Для этого нужно посмотреть контекст его использования. Если класс используется разными клиентами, это может говорить о слишком большом числе обязанностей, поэтому его нужно упростить. В некоторых случаях у класса может быть одна обязанность, которая рассматривается клиентами с разных точек зрения. Тогда это нужно выразить явно путем реализации двух или более интерфейсов.
Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 20.
День четыреста шестьдесят восьмой. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
39. Улучшайте Код, Сокращая Его
Краткость – сестра таланта. Это довольно банальный принцип, но иногда это действительно так.
Одно из улучшений, которые я внёс в наш код за последние несколько недель, - это удаление некоторых его частей.
Мы написали ПО в соответствии с принципами экстремального программирования, включая YAGNI (You Ain’t Gonna Need It – Вам Это Не Потребуется). Но человеческую природу не изменить, мы всё равно отступили от принципов в нескольких местах.
Я заметил, что выполнение определённых задач (простых задач, которые должны были исполняться почти мгновенно) занимало слишком много времени. Это было потому, что они страдали от оверинжиниринга: содержали кучу дополнительных прибамбасов, которые им не требовались, но в то время казались хорошей идеей.
Таким образом, я упростил код, улучшил производительность продукта и снизил уровень глобальной энтропии кода, просто удалив излишние функции. Особенно порадовало, что, судя по моим модульным тестам, я ничего не сломал во время этой операции.
Простая и приносящая удовлетворение от работы задача.
Так почему же ненужный код вообще появился? Почему программист почувствовал необходимость написать дополнительный код, и как такой код прошёл обзор? Почти наверняка это было примерно так.
- Один сказал: «Это просто крутая фича, которую я захотел написать.»
Совет №1: Пишите код, который добавляет ценность, а не просто потому, что вам хочется что-то реализовать.
- Другой подумал, что это может понадобиться в будущем, поэтому посчитал, что лучше всего реализовать это сейчас.
Совет №2: Это не YAGNI. Если вам это не нужно прямо сейчас, не пишите это прямо сейчас.
- Третий решил, что это небольшое дополнение, которое проще реализовать, чем спрашивать клиента, чтобы узнать, действительно ли оно необходимо.
Совет №3: Для написания и поддержки дополнительного кода всегда требуется больше времени. И клиент чаще всего вполне доступен. Небольшой, дополнительный кусочек кода со временем превращается в большой и требующий обслуживания.
- Четвёртый изобрёл дополнительные требования, которые не были ни документированы, ни обсуждены, чтобы оправдать дополнительную функциональность. Требования на самом деле не существовало.
Совет №4: Программисты не диктуют системные требования, их диктует клиент.
Над чем ты сейчас работаешь? Это точно нужно?
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Pete Goodliffe
97 Вещей, Которые Должен Знать Каждый Программист
39. Улучшайте Код, Сокращая Его
Краткость – сестра таланта. Это довольно банальный принцип, но иногда это действительно так.
Одно из улучшений, которые я внёс в наш код за последние несколько недель, - это удаление некоторых его частей.
Мы написали ПО в соответствии с принципами экстремального программирования, включая YAGNI (You Ain’t Gonna Need It – Вам Это Не Потребуется). Но человеческую природу не изменить, мы всё равно отступили от принципов в нескольких местах.
Я заметил, что выполнение определённых задач (простых задач, которые должны были исполняться почти мгновенно) занимало слишком много времени. Это было потому, что они страдали от оверинжиниринга: содержали кучу дополнительных прибамбасов, которые им не требовались, но в то время казались хорошей идеей.
Таким образом, я упростил код, улучшил производительность продукта и снизил уровень глобальной энтропии кода, просто удалив излишние функции. Особенно порадовало, что, судя по моим модульным тестам, я ничего не сломал во время этой операции.
Простая и приносящая удовлетворение от работы задача.
Так почему же ненужный код вообще появился? Почему программист почувствовал необходимость написать дополнительный код, и как такой код прошёл обзор? Почти наверняка это было примерно так.
- Один сказал: «Это просто крутая фича, которую я захотел написать.»
Совет №1: Пишите код, который добавляет ценность, а не просто потому, что вам хочется что-то реализовать.
- Другой подумал, что это может понадобиться в будущем, поэтому посчитал, что лучше всего реализовать это сейчас.
Совет №2: Это не YAGNI. Если вам это не нужно прямо сейчас, не пишите это прямо сейчас.
- Третий решил, что это небольшое дополнение, которое проще реализовать, чем спрашивать клиента, чтобы узнать, действительно ли оно необходимо.
Совет №3: Для написания и поддержки дополнительного кода всегда требуется больше времени. И клиент чаще всего вполне доступен. Небольшой, дополнительный кусочек кода со временем превращается в большой и требующий обслуживания.
- Четвёртый изобрёл дополнительные требования, которые не были ни документированы, ни обсуждены, чтобы оправдать дополнительную функциональность. Требования на самом деле не существовало.
Совет №4: Программисты не диктуют системные требования, их диктует клиент.
Над чем ты сейчас работаешь? Это точно нужно?
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Pete Goodliffe
День четыреста шестьдесят девятый. #ЧтоНовенького
Настройка Сервисов Azure и Эмуляторов Сервисов в Visual Studio
Начиная с Visual Studio 16.6 Preview 2, вкладка Подключенные Службы (Connected Services) окна Публикация (Publish) предлагает новый интерфейс под названием Зависимости Служб (Service Dependencies). Вы можете использовать его для подключения своего приложения к сервисам Azure (Azure SQL, Storage, Key Vault и др.). Там, где это возможно, также доступны варианты локальной эмуляции.
Добавление Новой Зависимости
Вы можете легко и быстро добавлять в ваш проект нужные пакеты NuGet, стартовый код и конфигурацию для каждой поддерживаемой службы Azure. Достаточно нажать +, выбрать сервис из списка и выполнить 2-3 шага в мастере (см. картинку ниже). Можно использовать как готовую службу Azure, так и настроить новую, не покидая IDE. Кроме того, использование Visual Studio для публикации приложения в Azure App Service даёт возможность настроить зависимости для удалённой среды, в которой вы публикуетесь.
Как Это Работает
Visual Studio создаёт два новых файла, которые можно найти в Обозревателе Решения в папке Свойства (Properties):
Ссылки на Службы
Также на вкладке Подключенные Службы теперь отображается блок «Ссылки на Службы OpenAPI и gRPC», а контекстное меню
Источник: https://devblogs.microsoft.com/aspnet/configuring-azure-services-and-emulators-using-visual-studio/
Настройка Сервисов Azure и Эмуляторов Сервисов в Visual Studio
Начиная с Visual Studio 16.6 Preview 2, вкладка Подключенные Службы (Connected Services) окна Публикация (Publish) предлагает новый интерфейс под названием Зависимости Служб (Service Dependencies). Вы можете использовать его для подключения своего приложения к сервисам Azure (Azure SQL, Storage, Key Vault и др.). Там, где это возможно, также доступны варианты локальной эмуляции.
Добавление Новой Зависимости
Вы можете легко и быстро добавлять в ваш проект нужные пакеты NuGet, стартовый код и конфигурацию для каждой поддерживаемой службы Azure. Достаточно нажать +, выбрать сервис из списка и выполнить 2-3 шага в мастере (см. картинку ниже). Можно использовать как готовую службу Azure, так и настроить новую, не покидая IDE. Кроме того, использование Visual Studio для публикации приложения в Azure App Service даёт возможность настроить зависимости для удалённой среды, в которой вы публикуетесь.
Как Это Работает
Visual Studio создаёт два новых файла, которые можно найти в Обозревателе Решения в папке Свойства (Properties):
serviceDependencies.json
и serviceDependencies.local.json
. Эти файлы безопасны для публикации. Кроме того Visual Studio создаёт файл serviceDependencies.local.json.user
, который по умолчанию не отображается в Обозревателе Решения и содержит информацию, которую можно считать секретной (например, идентификаторы ресурсов в Azure), и его публиковать не рекомендуется.Ссылки на Службы
Также на вкладке Подключенные Службы теперь отображается блок «Ссылки на Службы OpenAPI и gRPC», а контекстное меню
Добавить > Ссылка на Службу…
(Add > Service Reference…
) в Обозревателе Решения теперь ведёт на эту вкладку.Источник: https://devblogs.microsoft.com/aspnet/configuring-azure-services-and-emulators-using-visual-studio/
День четыреста семидесятый. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по ООП. 26-30.
26. Что Такое Паттерн Проектирования?
Паттерн проектирования в объектно-ориентированном мире - это предназначенное для многоразового использования решение типичных проблем проектирования ПО, которые часто возникают при разработке реальных приложений. Это шаблон или обобщённое описание решения проблемы, которое можно использовать во многих ситуациях.
27. Какие Типы Паттернов Проектирования Вы Знаете?
- Порождающие: отвечают за удобное и безопасное создание новых объектов или даже целых семейств объектов (Абстрактная фабрика, Фабричный метод, Строитель, Одиночка).
- Структурные: отвечают за построение удобных в поддержке иерархий классов (Адаптер, Декоратор, Компоновщик, Заместитель, Фасад).
- Поведенческие: решают задачи эффективного и безопасного взаимодействия между объектами программы (Стратегия, Шаблонный метод, Посредник , Итератор, Наблюдатель, Посетитель, Команда, Состояние, Цепочка обязанностей).
28. Каковы Основные Преимущества Использования Паттернов Проектирования?
- дают разработчику набор проверенных решений для использования;
- широко протестированы, поэтому снижают технический риск для проекта;
- могут применяться в любом объектно-ориентированном языке;
- упрощают общение, т.к. широко известны и хорошо документированы;
- очень гибкие и могут использоваться практически в любом приложении или домене.
29. В Чём Разница Между Статическим Классом и Одиночкой?
- В C# статический класс не может реализовывать интерфейс. Тогда как, если вам нужно, чтобы единичный экземпляр класса реализовывал интерфейс, вы можете использовать паттерн Одиночка без статического класса.
- Вы можете клонировать объект Одиночки, но вы не можете клонировать объект статического класса.
- Объект-одиночка может быть инициализирован лениво или асинхронно, в то время как статический класс обычно инициализируется при загрузке модуля.
30. Почему паттерн Одиночка считается анти-паттерном?
- Объект-одиночку сложно тестировать.
- Вы не можете контролировать его создание.
- Он может сохранять состояние между вызовами.
- Память, выделенная для объекта-одиночки, не может быть освобождена.
- В многопоточной среде доступ к такому объекту, возможно, придётся синхронизировать.
- Одиночки способствуют тесной связанности между классами, что ещё больше усложняет тестирование.
Подробнее…
Источник: https://www.c-sharpcorner.com
Самые часто задаваемые вопросы на собеседовании по ООП. 26-30.
26. Что Такое Паттерн Проектирования?
Паттерн проектирования в объектно-ориентированном мире - это предназначенное для многоразового использования решение типичных проблем проектирования ПО, которые часто возникают при разработке реальных приложений. Это шаблон или обобщённое описание решения проблемы, которое можно использовать во многих ситуациях.
27. Какие Типы Паттернов Проектирования Вы Знаете?
- Порождающие: отвечают за удобное и безопасное создание новых объектов или даже целых семейств объектов (Абстрактная фабрика, Фабричный метод, Строитель, Одиночка).
- Структурные: отвечают за построение удобных в поддержке иерархий классов (Адаптер, Декоратор, Компоновщик, Заместитель, Фасад).
- Поведенческие: решают задачи эффективного и безопасного взаимодействия между объектами программы (Стратегия, Шаблонный метод, Посредник , Итератор, Наблюдатель, Посетитель, Команда, Состояние, Цепочка обязанностей).
28. Каковы Основные Преимущества Использования Паттернов Проектирования?
- дают разработчику набор проверенных решений для использования;
- широко протестированы, поэтому снижают технический риск для проекта;
- могут применяться в любом объектно-ориентированном языке;
- упрощают общение, т.к. широко известны и хорошо документированы;
- очень гибкие и могут использоваться практически в любом приложении или домене.
29. В Чём Разница Между Статическим Классом и Одиночкой?
- В C# статический класс не может реализовывать интерфейс. Тогда как, если вам нужно, чтобы единичный экземпляр класса реализовывал интерфейс, вы можете использовать паттерн Одиночка без статического класса.
- Вы можете клонировать объект Одиночки, но вы не можете клонировать объект статического класса.
- Объект-одиночка может быть инициализирован лениво или асинхронно, в то время как статический класс обычно инициализируется при загрузке модуля.
30. Почему паттерн Одиночка считается анти-паттерном?
- Объект-одиночку сложно тестировать.
- Вы не можете контролировать его создание.
- Он может сохранять состояние между вызовами.
- Память, выделенная для объекта-одиночки, не может быть освобождена.
- В многопоточной среде доступ к такому объекту, возможно, придётся синхронизировать.
- Одиночки способствуют тесной связанности между классами, что ещё больше усложняет тестирование.
Подробнее…
Источник: https://www.c-sharpcorner.com
День четыреста семьдесят первый. #MoreEffectiveCSharp
11. Используйте Необязательные Параметры, Чтобы Минимизировать Перегрузки Методов
C# позволяет указывать аргументы метода по позиции или по имени. Разработчики, вызывающие ваш API, могут использовать именованные параметры, хотите вы того или нет. Следующий метод:
Изменение имён параметров проявляется интересным образом. Имена параметров хранятся в MSIL только в месте вызова, но не в вызываемом коде. Вы можете изменить имена параметров и выпустить новую версию сборки, не нарушив работу её пользователей. Разработчики, использующие сборку, увидят проблему только когда решат перекомпилировать свой код, используя обновлённую версию. Существующие клиентские сборки продолжат работать правильно. Предположим, что вы изменили
Добавление параметров вызовет ошибку времени выполнения в клиентском коде. Необязательные параметры реализованы аналогично именованным параметрам. Вызывающий код будет содержать аннотации в MSIL, отражающие существование значений по умолчанию и их значения. Там эти значения будут использоваться для всех необязательных параметров, значения для которых не указаны явно. Следовательно добавление в метод параметров (даже со значениями по умолчанию) вызовет в клиентском коде ошибку времени выполнения. Однако добавление параметров со значениями по умолчанию не вызовет ошибку при перекомпиляции клиентского кода.
Итого:
- Для вашего первоначального релиза используйте необязательные и именованные параметры, чтобы предусмотреть любые комбинации параметров, которые ваши пользователи захотят использовать.
- При последующих изменениях создавайте перегрузки методов для добавления дополнительных параметров. Таким образом, существующие клиентские приложения продолжат работать.
- При последующих изменениях избегайте изменения имён параметров в открытых или защищённых методах. Теперь они являются частью вашего публичного интерфейса.
Источник: Bill Wagner “More Effective C#”. – 2nd ed. Глава 12.
11. Используйте Необязательные Параметры, Чтобы Минимизировать Перегрузки Методов
C# позволяет указывать аргументы метода по позиции или по имени. Разработчики, вызывающие ваш API, могут использовать именованные параметры, хотите вы того или нет. Следующий метод:
private void SetName(string lastName, string firstName) {…}можно вызвать с именованными параметрами:
SetName(lastName: "Иванов", firstName: "Иван");Это гарантирует, что при прочтении этого кода не возникнет вопроса, находятся ли параметры в правильном порядке. Разработчики будут использовать именованные параметры всякий раз, когда это повышает читаемость кода (фактически, всегда, когда метод принимает несколько параметров одного типа).
Изменение имён параметров проявляется интересным образом. Имена параметров хранятся в MSIL только в месте вызова, но не в вызываемом коде. Вы можете изменить имена параметров и выпустить новую версию сборки, не нарушив работу её пользователей. Разработчики, использующие сборку, увидят проблему только когда решат перекомпилировать свой код, используя обновлённую версию. Существующие клиентские сборки продолжат работать правильно. Предположим, что вы изменили
SetName()
:public void SetName(string last, string first)Вы можете скомпилировать и выпустить новую версию этой сборки. Любые сборки, которые вызывают этот метод, будут продолжать работать, но, когда разработчики сошлются на обновлённую сборку, следующий код больше не скомпилируется:
SetName(lastName: "Иванов", firstName: "Иван");Применение именованных параметров совместно с необязательными параметрами (со значениями по умолчанию) позволяет клиенту API указывать только те параметры, которые он хочет переопределить. Это проще, чем использовать множество перегрузок. Например, метод:
public void SetName(string last = "Иванов",можно вызвать, либо вообще без параметров:
string first = "Иван") {…}
SetName();либо переопределив только имя:
SetName(first: "Олег");При этом изменение значений по умолчанию параметров метода потребует перекомпиляции вызывающего кода для отражения изменений. Существующие вызывающие сборки продолжат использовать предыдущее значение по умолчанию.
Добавление параметров вызовет ошибку времени выполнения в клиентском коде. Необязательные параметры реализованы аналогично именованным параметрам. Вызывающий код будет содержать аннотации в MSIL, отражающие существование значений по умолчанию и их значения. Там эти значения будут использоваться для всех необязательных параметров, значения для которых не указаны явно. Следовательно добавление в метод параметров (даже со значениями по умолчанию) вызовет в клиентском коде ошибку времени выполнения. Однако добавление параметров со значениями по умолчанию не вызовет ошибку при перекомпиляции клиентского кода.
Итого:
- Для вашего первоначального релиза используйте необязательные и именованные параметры, чтобы предусмотреть любые комбинации параметров, которые ваши пользователи захотят использовать.
- При последующих изменениях создавайте перегрузки методов для добавления дополнительных параметров. Таким образом, существующие клиентские приложения продолжат работать.
- При последующих изменениях избегайте изменения имён параметров в открытых или защищённых методах. Теперь они являются частью вашего публичного интерфейса.
Источник: Bill Wagner “More Effective C#”. – 2nd ed. Глава 12.
День четыреста семьдесят второй. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
40. Установи Меня
Я не просто так зашёл поинтересоваться вашей программой.
Я по уши в проблемах и у меня есть список дел в километр длиной. Единственная причина, по которой я сейчас на вашем сайте, заключается в том, что до меня дошли слухи о том, что все мои проблемы будут устранены с помощью вашего ПО. Простите, но пока я к этому отношусь скептически.
Если исследования по отслеживанию движения глазных яблок верны, на данный момент я уже прочитал заголовок и сканирую текст в поисках ссылки «Загрузить сейчас». Кроме того, если я зашёл на эту страницу с браузера под Linux и российским IP-адресом, скорее всего, я бы хотел получить версию ПО под Linux на русском языке с европейского зеркала, поэтому, пожалуйста, не спрашивайте меня об этом лишний раз. Мне нужно только нажать на ссылку, чтобы нужный файл скачался в папку Загрузки и продолжить чтение.
Мы все постоянно проводим анализ затрат и выгод от всего, что мы делаем. Если изучение вашего проекта превысит мой порог необходимых затрат хотя бы на секунду, я откажусь от него и пойду искать что-то ещё. Мгновенная выгода всегда лучше.
Первое препятствие - установка. Не думаете, что это большая проблема? Перейдите в папку загрузок посмотрите, что там творится. Куча архивов, верно? Какой процент из них вы распаковали? Сколько из этого вы установили? Лично я от силы треть, остальные просто бесполезно занимают место на диске.
Я хочу безболезненной установки, но при этом не хочу, чтобы вы входили в мой дом без приглашения. Прежде чем установить что-то, я бы хотел точно знать, куда вы распакуете файлы. Это мой компьютер, и я люблю держать его в чистоте, когда могу. Я также хочу иметь возможность удалить вашу программу, если разочаруюсь в ней. Если я подозреваю, что с этим могут быть проблемы, я не стану её устанавливать. Моя машина сейчас стабильна, и я хочу сохранить её в таком состоянии.
Если у вашей программы есть графический интерфейс, то я хочу сделать что-то простое и увидеть результат. Мастеры не помогают, потому что они делают вещи, которых я не понимаю. Чтобы сделать что-то простое, я не хочу создавать проекты, импортировать библиотеки или сообщать вам свой адрес электронной почты. Если простой пример сработает, я пойду искать подробности в мануале.
Если ваше ПО является библиотекой, то я продолжу читать вашу веб-страницу в поисках краткого мануала. Я хочу получить эквивалент «Hello world» в трёх строчках простого кода, с описанием того, что должно получиться. Без огромных шаблонов или длительных настроек, только один скрипт. Помните, что я также скачал библиотеку ваших конкурентов. Ту, про которую на форумах пишут, что она намного лучше вашей. Если этот скрипт сработает, я пойду искать подробности в мануале.
Мануал же есть, не так ли? И такой, который легко понять?
И если в мануале описана моя проблема, это поднимет мне настроение. Теперь, когда я читаю о том, что я могу сделать с помощью вашего ПО, это начинает становиться интересным. Я почитаю мануал, потягивая чай или кофе(или что покрепче), поиграю с примерами и научусь использовать ваш продукт. Если это решит мою проблему, я отправлю вам благодарственное письмо или донат, буду отправлять вам отчёты об ошибках и предложениях по новым функциям. Я даже расскажу всем своим друзьям, что ваше ПО лучше, хотя я никогда не пробовал продукт вашего конкурента. Но всё зависит от того, насколько вы позаботились о моих первых пробных шагах.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Marcus Baker
97 Вещей, Которые Должен Знать Каждый Программист
40. Установи Меня
Я не просто так зашёл поинтересоваться вашей программой.
Я по уши в проблемах и у меня есть список дел в километр длиной. Единственная причина, по которой я сейчас на вашем сайте, заключается в том, что до меня дошли слухи о том, что все мои проблемы будут устранены с помощью вашего ПО. Простите, но пока я к этому отношусь скептически.
Если исследования по отслеживанию движения глазных яблок верны, на данный момент я уже прочитал заголовок и сканирую текст в поисках ссылки «Загрузить сейчас». Кроме того, если я зашёл на эту страницу с браузера под Linux и российским IP-адресом, скорее всего, я бы хотел получить версию ПО под Linux на русском языке с европейского зеркала, поэтому, пожалуйста, не спрашивайте меня об этом лишний раз. Мне нужно только нажать на ссылку, чтобы нужный файл скачался в папку Загрузки и продолжить чтение.
Мы все постоянно проводим анализ затрат и выгод от всего, что мы делаем. Если изучение вашего проекта превысит мой порог необходимых затрат хотя бы на секунду, я откажусь от него и пойду искать что-то ещё. Мгновенная выгода всегда лучше.
Первое препятствие - установка. Не думаете, что это большая проблема? Перейдите в папку загрузок посмотрите, что там творится. Куча архивов, верно? Какой процент из них вы распаковали? Сколько из этого вы установили? Лично я от силы треть, остальные просто бесполезно занимают место на диске.
Я хочу безболезненной установки, но при этом не хочу, чтобы вы входили в мой дом без приглашения. Прежде чем установить что-то, я бы хотел точно знать, куда вы распакуете файлы. Это мой компьютер, и я люблю держать его в чистоте, когда могу. Я также хочу иметь возможность удалить вашу программу, если разочаруюсь в ней. Если я подозреваю, что с этим могут быть проблемы, я не стану её устанавливать. Моя машина сейчас стабильна, и я хочу сохранить её в таком состоянии.
Если у вашей программы есть графический интерфейс, то я хочу сделать что-то простое и увидеть результат. Мастеры не помогают, потому что они делают вещи, которых я не понимаю. Чтобы сделать что-то простое, я не хочу создавать проекты, импортировать библиотеки или сообщать вам свой адрес электронной почты. Если простой пример сработает, я пойду искать подробности в мануале.
Если ваше ПО является библиотекой, то я продолжу читать вашу веб-страницу в поисках краткого мануала. Я хочу получить эквивалент «Hello world» в трёх строчках простого кода, с описанием того, что должно получиться. Без огромных шаблонов или длительных настроек, только один скрипт. Помните, что я также скачал библиотеку ваших конкурентов. Ту, про которую на форумах пишут, что она намного лучше вашей. Если этот скрипт сработает, я пойду искать подробности в мануале.
Мануал же есть, не так ли? И такой, который легко понять?
И если в мануале описана моя проблема, это поднимет мне настроение. Теперь, когда я читаю о том, что я могу сделать с помощью вашего ПО, это начинает становиться интересным. Я почитаю мануал, потягивая чай или кофе
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Marcus Baker
День четыреста семьдесят третий. #ЗаметкиНаПолях
Обнуляемые Ссылочные Типы в C# 8
Иногда
Чтобы включить эту функцию, необходимо добавить следующую строку в
Методам и аргументам можно добавить аннотации с помощью атрибутов из пространства имён System.Diagnostics.CodeAnalysis, чтобы помочь компилятору анализировать поток исполнения относительно обнуляемых типов. Базовые библиотеки .NET Core содержат эти атрибуты. Например:
Эти атрибуты доступны в .NET Core 3.x, .NET Standard 2.1 и .NET 5.0.
Источник: https://developers.redhat.com/blog/2020/03/05/c-8-nullable-reference-types/
Обнуляемые Ссылочные Типы в C# 8
Иногда
null
является приемлемым значением для ссылочных типов, но часто это недопустимое значение, которое приводит к ArgumentNullException
и NullReferenceException
. C# 8 даёт нам возможность выразить, может ли ссылочная переменная быть null
. Основываясь на этих аннотациях, компилятор предупредит вас, когда вы потенциально используете пустую ссылку или передаёте пустую ссылку в функцию, которая не может принимать null
.Чтобы включить эту функцию, необходимо добавить следующую строку в
PropertyGroup
файла проекта (.csproj
):<Nullable>enable</Nullable>Для обозначения типов, допускающих
null
, используется тот же символ ?
, как и для обнуляемых значимых типов.MyClass? mayBeNull = null;Также можно использовать оператор null-объединения:
MyClass mayNotBeNull = new MyClass();
mayNotBeNull = mayBeNull ?? new MyClass();Компилятор не просто полагается на определение, он использует анализ потока, чтобы определить места в коде, где необнуляемой переменной можно безопасно присвоить значение. Например, следующий код не вызовет предупреждений:
if (mayBeNull == null)Но, если проверку убрать, компилятор выдаст предупреждение:
throw new ArgumentNullException(nameof(mayBeNull));
mayNotBeNull = mayBeNull;
CS8600: Converting null literal or possible null value to non-nullable type. (Преобразование null или пустой ссылки в необнуляемый тип)В случаях, когда компилятор не сможет выявить, что ссылка не допускает
null
, но вы уверены в безопасности кода, можно использовать «null-снисходительный» (null-forgiving) оператор !
(заметьте, что в отличие от оператора отрицания, он ставится после переменной, а не до):Uri? uri = …;Т.к. мы использовали оператор
string scheme = uri!.Scheme;
int port = uri.Port;
!
, компилятор знает, что это безопасно. Его уже не нужно использовать на следующей строке при обращении к свойству Port
(компилятор делает вывод, что uri
больше не может быть null
).Методам и аргументам можно добавить аннотации с помощью атрибутов из пространства имён System.Diagnostics.CodeAnalysis, чтобы помочь компилятору анализировать поток исполнения относительно обнуляемых типов. Базовые библиотеки .NET Core содержат эти атрибуты. Например:
public static bool IsNullOrEmpty([NotNullWhenAttribute(false)] string? value)Такая аннотация сообщает компилятору, что, когда метод возвращает
false
, переменная, переданная в value
, далее в коде не будет иметь значение null
, даже при том, что она обнуляемого типа.Эти атрибуты доступны в .NET Core 3.x, .NET Standard 2.1 и .NET 5.0.
Источник: https://developers.redhat.com/blog/2020/03/05/c-8-nullable-reference-types/
День четыреста семьдесят четвёртый. #DesignPatterns
Принципы SOLID.
5. Принцип инверсии зависимостей (DIP)
«Модули верхнего уровня не должны зависеть от модулей нижнего уровня. И те и другие должны зависеть от абстракций. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций» (Мартин Р. Принципы, паттерны и практики гибкой разработки. — 2006).
Принцип инверсии зависимостей лежит в основе популярных техник внедрения зависимостей (Dependency Injection). В основе принципа инверсии зависимостей лежит идея использования интерфейсов. Одна группа классов реализует некоторый набор интерфейсов, а другая — принимает эти интерфейсы в качестве аргументов конструктора.
Однако не стоит забывать, что наличие интерфейсов образует дополнительный уровень абстракции, что затрудняет понимание системы. Не для всех классов нужно выделять интерфейсы, и не все зависимости следует требовать извне в виде интерфейсов.
Слои
Любое современное приложение разбито на слои, каждый из которых отвечает за определенный аспект поведения: доступа к данным, бизнес-логики, UI и т.п. Каждый слой отвечает за определенную область и использует сервисы нижележащих уровней для решения своих задач. Принцип SRP говорит, что каждый класс, модуль или слой должен решать лишь одну задачу. Это значит, что код доступа к данным не должен содержать бизнес-логики, а бизнес-логика не должна знать о UI. Слои нижнего уровня не знают и не должны знать о слоях верхнего уровня. Это позволяет использовать низкоуровневые слои повторно, упрощает понимание и развитие каждого из них, а также ограничивает распространение изменений.
Для чего нужен DIP
DIP предназначен для устранения прямых связей между классами или модулями с зависимостями более высокого уровня. Название отражает нетипичность направления зависимостей: классы нижнего уровня определяют некоторый контракт, которому должны следовать классы верхнего уровня. Классы верхнего уровня вынуждены выступать в роли адаптеров и подстраиваться под протокол, определенный на уровне ниже.
Примеры нарушения DIP
1. Низкоуровневые классы напрямую общаются с высокоуровневыми классами: модели в MVC знают о UI или код доступа к данным знает о бизнес-логике.
2. Классы принимают слишком низкоуровневые интерфейсы, такие как
Принцип DIP не сводится лишь к выделению интерфейсов и передаче их через конструктор. DIP объясняет, для чего нужно это делать. Классы имеют право контролировать свои детали реализации, но некоторые аспекты находятся за пределами их компетенции. Чтобы не завязываться на классы верхнего уровня, класс может объявить некоторый интерфейс и потребовать его экземпляр через аргументы конструктора. Таким образом мы можем инвертировать зависимости и позволить классам нижних уровней взаимодействовать с другими частями системы, ничего конкретного о них не зная.
Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 21.
Принципы SOLID.
5. Принцип инверсии зависимостей (DIP)
«Модули верхнего уровня не должны зависеть от модулей нижнего уровня. И те и другие должны зависеть от абстракций. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций» (Мартин Р. Принципы, паттерны и практики гибкой разработки. — 2006).
Принцип инверсии зависимостей лежит в основе популярных техник внедрения зависимостей (Dependency Injection). В основе принципа инверсии зависимостей лежит идея использования интерфейсов. Одна группа классов реализует некоторый набор интерфейсов, а другая — принимает эти интерфейсы в качестве аргументов конструктора.
interface IReader {Использование интерфейсов приводит к слабосвязанному (loosely coupled) дизайну, поскольку класс
string Read();
}
class Report {
public Report(IReader reader) {…}
}
class FileReader : IReader {…}
Report
знает лишь об интерфейсе IReader
и не знает о конкретной реализации этого интерфейса. А следование принципу LSP позволит заменить одну реализацию другой и получить гибкое решение, соответствующее принципу OCP.Однако не стоит забывать, что наличие интерфейсов образует дополнительный уровень абстракции, что затрудняет понимание системы. Не для всех классов нужно выделять интерфейсы, и не все зависимости следует требовать извне в виде интерфейсов.
Слои
Любое современное приложение разбито на слои, каждый из которых отвечает за определенный аспект поведения: доступа к данным, бизнес-логики, UI и т.п. Каждый слой отвечает за определенную область и использует сервисы нижележащих уровней для решения своих задач. Принцип SRP говорит, что каждый класс, модуль или слой должен решать лишь одну задачу. Это значит, что код доступа к данным не должен содержать бизнес-логики, а бизнес-логика не должна знать о UI. Слои нижнего уровня не знают и не должны знать о слоях верхнего уровня. Это позволяет использовать низкоуровневые слои повторно, упрощает понимание и развитие каждого из них, а также ограничивает распространение изменений.
Для чего нужен DIP
DIP предназначен для устранения прямых связей между классами или модулями с зависимостями более высокого уровня. Название отражает нетипичность направления зависимостей: классы нижнего уровня определяют некоторый контракт, которому должны следовать классы верхнего уровня. Классы верхнего уровня вынуждены выступать в роли адаптеров и подстраиваться под протокол, определенный на уровне ниже.
Примеры нарушения DIP
1. Низкоуровневые классы напрямую общаются с высокоуровневыми классами: модели в MVC знают о UI или код доступа к данным знает о бизнес-логике.
2. Классы принимают слишком низкоуровневые интерфейсы, такие как
IFileStream
, что может привести к подрыву инкапсуляции и излишнему увеличению сложности.Принцип DIP не сводится лишь к выделению интерфейсов и передаче их через конструктор. DIP объясняет, для чего нужно это делать. Классы имеют право контролировать свои детали реализации, но некоторые аспекты находятся за пределами их компетенции. Чтобы не завязываться на классы верхнего уровня, класс может объявить некоторый интерфейс и потребовать его экземпляр через аргументы конструктора. Таким образом мы можем инвертировать зависимости и позволить классам нижних уровней взаимодействовать с другими частями системы, ничего конкретного о них не зная.
Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 21.
15-18 июня состоится масштабная онлайн-конференция DotNext 2020 Piter.
Что будет:
— Десятки докладов от экспертов со всего мира о самом актуальном: настоящее и будущее платформы .NET, оптимизация производительности, внутреннее устройство платформы, архитектура и паттерны проектирования;
— Интервью, развлекательные подкасты, технические ток-шоу и дискуссии со спикерами;
— Конференция будет идти 4 дня. Чтобы участники не устали, мы разбили программу на блоки по 4-5 часов;
— Каждый день — несколько параллельных треков, между которыми можно переключаться, а доклады перематывать или ставить на паузу;
— Розыгрыши с призами от партнеров конференции;
— Обсуждение докладов с коллегами и единомышленниками.
Среди спикеров DotNext 2020 Piter:
— Скотт Хансельман (Scott Hanselman), автор книг ASP.NET 4.5 in C# and VB, ASP.NET MVC 4.5, Relationship Hacks, ведущий собственного блога: www.hanselman.com.
— Джон Скит (Jon Skeet), Microsoft MVP более 13 лет, №1 на StackOverflow, автор блога C# in Depth.
— Андрей Акиньшин, Microsoft .NET MVP, автор книги «Pro .NET Benchmarking», мейнтейнер проекта BenchmarkDotNet, работает в JetBrains над проектом Rider (кроссплатформенная .NET IDE, основанная на платформе IntelliJ и ReSharper).
— Джеф Просайс (Jeff Prosise), cооснователь Wintellect, автор более девяти книг по разработке приложений.
— Алекс Тиссен (Alex Thissen), тринадцатикратный Microsoft MVP в Visual Studio и Development Technologies.
— Стефан Клири (Stephen Cleary), Microsoft MVP и автор книги «Concurrency in C# Cookbook».
Билет со скидкой по промокоду NetDevDiary20pc: https://bit.ly/3940lZV
Что будет:
— Десятки докладов от экспертов со всего мира о самом актуальном: настоящее и будущее платформы .NET, оптимизация производительности, внутреннее устройство платформы, архитектура и паттерны проектирования;
— Интервью, развлекательные подкасты, технические ток-шоу и дискуссии со спикерами;
— Конференция будет идти 4 дня. Чтобы участники не устали, мы разбили программу на блоки по 4-5 часов;
— Каждый день — несколько параллельных треков, между которыми можно переключаться, а доклады перематывать или ставить на паузу;
— Розыгрыши с призами от партнеров конференции;
— Обсуждение докладов с коллегами и единомышленниками.
Среди спикеров DotNext 2020 Piter:
— Скотт Хансельман (Scott Hanselman), автор книг ASP.NET 4.5 in C# and VB, ASP.NET MVC 4.5, Relationship Hacks, ведущий собственного блога: www.hanselman.com.
— Джон Скит (Jon Skeet), Microsoft MVP более 13 лет, №1 на StackOverflow, автор блога C# in Depth.
— Андрей Акиньшин, Microsoft .NET MVP, автор книги «Pro .NET Benchmarking», мейнтейнер проекта BenchmarkDotNet, работает в JetBrains над проектом Rider (кроссплатформенная .NET IDE, основанная на платформе IntelliJ и ReSharper).
— Джеф Просайс (Jeff Prosise), cооснователь Wintellect, автор более девяти книг по разработке приложений.
— Алекс Тиссен (Alex Thissen), тринадцатикратный Microsoft MVP в Visual Studio и Development Technologies.
— Стефан Клири (Stephen Cleary), Microsoft MVP и автор книги «Concurrency in C# Cookbook».
Билет со скидкой по промокоду NetDevDiary20pc: https://bit.ly/3940lZV
DotNext 2021 Piter. Конференция для .NET-разработчиков. 20-23 апреля, онлайн.
.NET-конференция. 20-23 апреля, онлайн. 4 дня и несколько десятков технических докладов.
День четыреста семьдесят пятый. #DesignPatterns
Принцип инверсии зависимостей (DIP). Примечание
DI vs. DIP vs. IoC
Существуют три схожих понятия, связанных с передачей зависимостей, в каждом из которых есть слово «инверсия» (inversion) или «зависимость» (dependency):
1. IoC — Inversion of Control (инверсия управления);
2. DI — Dependency Injection (внедрение зависимостей);
3. DIP — Dependency Inversion Principle (принцип инверсии зависимостей).
Эти термины часто используют несогласованно или путают.
1. Inversion of Control
Инверсия управления — это некий абстрактный принцип, набор рекомендаций для написания слабо связанного кода. В обычной программе программист сам решает, в какой последовательности делать вызовы процедур. Но, если используется фреймворк, программист может разместить свой код в определённых точках выполнения (используя функции обратного вызова или подобные механизмы), затем запустить «главную функцию» фреймворка, которая обеспечит всё выполнение и будет вызывать код программиста тогда, когда это будет необходимо. Как следствие, происходит утеря контроля над выполнением кода — это и называется инверсией управления (фреймворк управляет кодом программиста, а не программист управляет фреймворком).
IoC-контейнер – это фреймворк для реализации автоматического внедрения зависимостей. Он управляет созданием, жизненным циклом объектов и внедрением зависимостей в класс, тем самым «изымая» контроль над зависимостями из класса.
2. Dependency Injection
Внедрение зависимостей — это механизм передачи классу его зависимостей:
- Через конструктор (Constructor Injection) передаются обязательные зависимости класса, без которых работа класса невозможна.
- Через метод (Method Injection) передаются зависимости, которые нужны лишь одному методу, а не всем методам класса.
- Через свойство (Property Injection) чаще устанавливаются лишь необязательные зависимости (обычно инфраструктурные), для которых существует значение по умолчанию (например, свойство
Очень важно понимать, что DI-паттерны не говорят о том, как должна выглядеть зависимость, к какому уровню она относится, сколько их должно быть и т. п. Это лишь инструмент передачи зависимостей от одного класса другому.
3. Dependency Inversion Principle
Принцип инверсии зависимости говорит о том, какого вида зависимости необходимо передавать классу извне, а какие зависимости класс должен создавать самостоятельно. Важно, чтобы зависимости класса были понятны и важны вызывающему коду. Зависимости класса должны располагаться на текущем или более высоком уровне абстракции. Другими словами, не любой класс, которого требует интерфейс в конструкторе, следует принципу инверсии зависимостей.
Например, в класс создания отчётов можно внедрить зависимости от
уровня формирования и отправки отчетов и не соответствуют принципу инверсии зависимостей, поскольку оперируют более низкоуровневыми понятиями, чем требуется. На этом уровне нужно оперировать не строками и сокетами, а отчетами. В результате в данном примере используется внедрение зависимостей (DI), но данный код не следует принципу инверсии зависимостей (DIP).
Итого
Инверсия управления (IoC) говорит об изменении потока исполнения, присуща фреймворкам и функциям обратного вызова и не имеет прямого отношения к управлению зависимостями. Внедрение зависимостей (DI) — это инструмент передачи классу его зависимости через конструктор, метод или свойство. Принцип инверсии зависимостей (DIP) — это принцип проектирования, который говорит, что классы должны зависеть от высокоуровневых абстракций.
Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 21.
Принцип инверсии зависимостей (DIP). Примечание
DI vs. DIP vs. IoC
Существуют три схожих понятия, связанных с передачей зависимостей, в каждом из которых есть слово «инверсия» (inversion) или «зависимость» (dependency):
1. IoC — Inversion of Control (инверсия управления);
2. DI — Dependency Injection (внедрение зависимостей);
3. DIP — Dependency Inversion Principle (принцип инверсии зависимостей).
Эти термины часто используют несогласованно или путают.
1. Inversion of Control
Инверсия управления — это некий абстрактный принцип, набор рекомендаций для написания слабо связанного кода. В обычной программе программист сам решает, в какой последовательности делать вызовы процедур. Но, если используется фреймворк, программист может разместить свой код в определённых точках выполнения (используя функции обратного вызова или подобные механизмы), затем запустить «главную функцию» фреймворка, которая обеспечит всё выполнение и будет вызывать код программиста тогда, когда это будет необходимо. Как следствие, происходит утеря контроля над выполнением кода — это и называется инверсией управления (фреймворк управляет кодом программиста, а не программист управляет фреймворком).
IoC-контейнер – это фреймворк для реализации автоматического внедрения зависимостей. Он управляет созданием, жизненным циклом объектов и внедрением зависимостей в класс, тем самым «изымая» контроль над зависимостями из класса.
2. Dependency Injection
Внедрение зависимостей — это механизм передачи классу его зависимостей:
- Через конструктор (Constructor Injection) передаются обязательные зависимости класса, без которых работа класса невозможна.
- Через метод (Method Injection) передаются зависимости, которые нужны лишь одному методу, а не всем методам класса.
- Через свойство (Property Injection) чаще устанавливаются лишь необязательные зависимости (обычно инфраструктурные), для которых существует значение по умолчанию (например, свойство
Logger
содержит разумное значение по умолчанию, но в некоторых случаях может быть заменено присваиванием другого значения свойству).Очень важно понимать, что DI-паттерны не говорят о том, как должна выглядеть зависимость, к какому уровню она относится, сколько их должно быть и т. п. Это лишь инструмент передачи зависимостей от одного класса другому.
3. Dependency Inversion Principle
Принцип инверсии зависимости говорит о том, какого вида зависимости необходимо передавать классу извне, а какие зависимости класс должен создавать самостоятельно. Важно, чтобы зависимости класса были понятны и важны вызывающему коду. Зависимости класса должны располагаться на текущем или более высоком уровне абстракции. Другими словами, не любой класс, которого требует интерфейс в конструкторе, следует принципу инверсии зависимостей.
Например, в класс создания отчётов можно внедрить зависимости от
IStringBuilder
для построения текста отчёта, либо от ISocket
для отправки отчётов по сети. Но эти абстракции находятся на несколько уровней нижеуровня формирования и отправки отчетов и не соответствуют принципу инверсии зависимостей, поскольку оперируют более низкоуровневыми понятиями, чем требуется. На этом уровне нужно оперировать не строками и сокетами, а отчетами. В результате в данном примере используется внедрение зависимостей (DI), но данный код не следует принципу инверсии зависимостей (DIP).
Итого
Инверсия управления (IoC) говорит об изменении потока исполнения, присуща фреймворкам и функциям обратного вызова и не имеет прямого отношения к управлению зависимостями. Внедрение зависимостей (DI) — это инструмент передачи классу его зависимости через конструктор, метод или свойство. Принцип инверсии зависимостей (DIP) — это принцип проектирования, который говорит, что классы должны зависеть от высокоуровневых абстракций.
Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 21.
👍2
День четыреста семьдесят седьмой. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
41. Межпроцессное взаимодействие влияет на время отклика приложения
Время отклика – одно из наиболее важных качеств ПО. Мало что так расстраивает, как ожидание реакции программы на действие пользователя, особенно если это действие приходится делать постоянно. Мы чувствуем, как программа тратит наше время и влияет на нашу производительность. Однако причины большого времени отклика неочевидны, особенно в современных приложениях. Большая часть литературы по управлению производительностью по-прежнему фокусируется на эффективных структурах данных и алгоритмах. Это может влиять в некоторых случаях, но крайне маловероятно это будет решающим фактором, влияющим на производительность в современных многоуровневых корпоративных приложениях.
Гораздо больше на время отклика приложения влияет количество межпроцессных взаимодействий (interprocess communications - IPC), производимых в ответ на действие пользователя. Хотя могут быть и другие локальные узкие места, этот фактор обычно доминирует. Каждое удалённое межпроцессное взаимодействие вносит некоторую незначительную задержку в общее время отклика, и эти отдельные задержки суммируются, особенно когда они происходят последовательно.
Ярким примером является ленивая загрузка или загрузка по частям - последовательное выполнение нескольких запросов к базе для получения данных. Когда клиент базы данных является сервером приложений, отображающим веб-страницу, эти запросы к БД обычно выполняются последовательно в одном потоке. Их индивидуальные задержки накапливаются, увеличивая общее время отклика. Даже если каждый запрос к базе данных занимает всего 10 миллисекунд, страница, требующая 1000 вызовов (что не редкость), будет отображаться не меньше 10 секунд. Другие примеры включают вызов веб-службы, HTTP-запросы из веб-браузера, вызов распределённого объекта и т.п. Чем больше удаленных вызовов необходимо для ответа на действие пользователя, тем больше будет время отклика.
Существует несколько относительно очевидных и общеизвестных стратегий по сокращению количества IPC:
1. Оптимизировать взаимодействие и максимально снизить объём пересылаемых между процессами данных (получение данных в JSON вместо полной HTML-разметки; применение фильтрации данных в запросе к БД вместо запроса всех данных и фильтрации в приложении и т.п.)
2. По возможности распараллеливать межпроцессное взаимодействие, чтобы общее время отклика определялось главным образом запросом с наибольшей задержкой.
3. Кэшировать результаты предыдущих запросов, чтобы можно было избежать повторных запросов тех же данных и вместо этого использовать локальный кэш.
Когда вы разрабатываете приложение, помните о количестве межпроцессных взаимодействий в ответ на действие пользователя. Анализируя приложения, которые страдают от низкой производительности, я часто находил, что одно действие пользователя приводило к более чем тысяче межпроцессных взаимодействий. Уменьшение этого соотношения, будь то кэширование, распараллеливание или другой метод, принесет гораздо больше пользы, чем оптимизация структур данных или алгоритма сортировки.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Randy Stafford
97 Вещей, Которые Должен Знать Каждый Программист
41. Межпроцессное взаимодействие влияет на время отклика приложения
Время отклика – одно из наиболее важных качеств ПО. Мало что так расстраивает, как ожидание реакции программы на действие пользователя, особенно если это действие приходится делать постоянно. Мы чувствуем, как программа тратит наше время и влияет на нашу производительность. Однако причины большого времени отклика неочевидны, особенно в современных приложениях. Большая часть литературы по управлению производительностью по-прежнему фокусируется на эффективных структурах данных и алгоритмах. Это может влиять в некоторых случаях, но крайне маловероятно это будет решающим фактором, влияющим на производительность в современных многоуровневых корпоративных приложениях.
Гораздо больше на время отклика приложения влияет количество межпроцессных взаимодействий (interprocess communications - IPC), производимых в ответ на действие пользователя. Хотя могут быть и другие локальные узкие места, этот фактор обычно доминирует. Каждое удалённое межпроцессное взаимодействие вносит некоторую незначительную задержку в общее время отклика, и эти отдельные задержки суммируются, особенно когда они происходят последовательно.
Ярким примером является ленивая загрузка или загрузка по частям - последовательное выполнение нескольких запросов к базе для получения данных. Когда клиент базы данных является сервером приложений, отображающим веб-страницу, эти запросы к БД обычно выполняются последовательно в одном потоке. Их индивидуальные задержки накапливаются, увеличивая общее время отклика. Даже если каждый запрос к базе данных занимает всего 10 миллисекунд, страница, требующая 1000 вызовов (что не редкость), будет отображаться не меньше 10 секунд. Другие примеры включают вызов веб-службы, HTTP-запросы из веб-браузера, вызов распределённого объекта и т.п. Чем больше удаленных вызовов необходимо для ответа на действие пользователя, тем больше будет время отклика.
Существует несколько относительно очевидных и общеизвестных стратегий по сокращению количества IPC:
1. Оптимизировать взаимодействие и максимально снизить объём пересылаемых между процессами данных (получение данных в JSON вместо полной HTML-разметки; применение фильтрации данных в запросе к БД вместо запроса всех данных и фильтрации в приложении и т.п.)
2. По возможности распараллеливать межпроцессное взаимодействие, чтобы общее время отклика определялось главным образом запросом с наибольшей задержкой.
3. Кэшировать результаты предыдущих запросов, чтобы можно было избежать повторных запросов тех же данных и вместо этого использовать локальный кэш.
Когда вы разрабатываете приложение, помните о количестве межпроцессных взаимодействий в ответ на действие пользователя. Анализируя приложения, которые страдают от низкой производительности, я часто находил, что одно действие пользователя приводило к более чем тысяче межпроцессных взаимодействий. Уменьшение этого соотношения, будь то кэширование, распараллеливание или другой метод, принесет гораздо больше пользы, чем оптимизация структур данных или алгоритма сортировки.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Randy Stafford
День четыреста семьдесят восьмой. #ЗаметкиНаПолях
ASP.NET Core. Тег-хелперы. Начало
В ASP.NET Core на смену помощникам HTML пришли тег-хелперы (теги-помощники). Они позволяют изменять, дополнять или полностью заменять содержимое НТМL-элементов. Распространённые случаи использования: генерирование URL для форм и ссылок, привязка модели к элементам форм, согласованная стилизация элементов и т.п. Тег-хелперы позволяют получать более чистый и читаемый код HTML. Сравните:
Если элемент
то
2. Аналогично можно использовать эти тег-хелперы для элементов ссылок (класс
3. Тег-хелперы для работы с элементами
Кроме того, контролировать тип элемента
Аналогично тег-хелпер
Источник: Адам Фримен “Pro ASP.NET Core MVC 2”. – Диалектика, 2019. Главы 24, 25.
ASP.NET Core. Тег-хелперы. Начало
В ASP.NET Core на смену помощникам HTML пришли тег-хелперы (теги-помощники). Они позволяют изменять, дополнять или полностью заменять содержимое НТМL-элементов. Распространённые случаи использования: генерирование URL для форм и ссылок, привязка модели к элементам форм, согласованная стилизация элементов и т.п. Тег-хелперы позволяют получать более чистый и читаемый код HTML. Сравните:
@Html.BeginForm("Search", "Home", FormMethod.Post))и
<form asp-controller="Home" asp-action="Search" method="post">1. Тег-хелперы для работы с элементом
form
(класс FormTagHelper
):asp-controller
– контроллер для html-атрибута action
формы (если не указан, используется текущий контроллер).asp-action
– метод действия для html-атрибута action формы (если не указан, используется текущий метод действия).asp-route-*
– дополнительные значения URL в атрибуте action (например, asp-route-id
предоставляет системе маршрутизации значение сегмента id
).asp-route
– имя маршрута, для генерации URL в атрибуте action
.asp-area
– область в атрибуте action
.asp-antiforgery
– управляет добавлением информации, противодействующей подделке.Если элемент
form
не содержит явного html-атрибута action
, то
FormTagHelper
автоматически включает средство противостояния атакам CSRF. Когда значением атрибута asp-antiforgery
является false, маркеры безопасности будут отключены.2. Аналогично можно использовать эти тег-хелперы для элементов ссылок (класс
AnchorTagHelper
). Также для ссылок можно указать:asp-protocol
– протоколasp-host
– имя хостаasp-fragment
– фрагмент URL (часть после символа #
)3. Тег-хелперы для работы с элементами
input
(класс InputTagHelper
):asp-for
– свойство модели представления, которое представляет элемент input
.asp-format
– формат отображения данных (например, {0:#,###}
для отделения тысяч запятой).asp-for
автоматически устанавливает тип элемента input
в зависимости от типа данных модели:string
– type="text"
(обычное текстовое поле).byte
, int
, short
, long
– type="number"
(числовое поле).float
, double
, decimal
– type="text"
с дополнительной проверкой значения.bool
– type="checkbox"
(флажок).DateTime
– type="date"
(элемент выбора даты).Кроме того, контролировать тип элемента
input
можно с помощью атрибута свойств модели UIHint
:HiddenInput - type="hidden"
(скрытое поле)Password - type="password"
(поле пароля)PhoneNumber - type="tel"
(телефон)Url - type="url"
(URL)EmailAddress - type="email"
(email)Time - type="time"
(формат времени)Аналогично тег-хелпер
asp-for
можно использовать и для элементов label
, textarea
и select
. Кроме того, для отображения списка элементов option
элементу select
можно задать коллекцию значений с помощью asp-items
, передав в него экземпляр типа SelectList
:<select asp-for="Country" asp-items="@new SelectList(…)">Продолжение следует…
Источник: Адам Фримен “Pro ASP.NET Core MVC 2”. – Диалектика, 2019. Главы 24, 25.
День четыреста семьдесят девятый. #ЗаметкиНаПолях
ASP.NET Core. Тег-хелперы. Продолжение
4. Работа с файлами JS и CSS
Файлы JS и CSS на HTML страницу подключаются с помощью тегов
Кроме того, можно использовать несколько шаблонов через запятую.
Аналогично для файлов CSS используются
Группа тег-хелперов
Для проверки, загрузился ли внешний файл, в JS используется тег-хелпер
Для CSS всё немного сложнее. Нужно использовать 3 свойства: имя класса CSS, свойство и значение. В разметку будет добавлен JS код, который проверит, соответствует ли значение заданного свойства заданного CSS-класса значению, указанному в тег-хелпере. Если нет (стили не были применены, т.к. файл не удалось загрузить), будет использован локальный файл. Например:
Отдельные части веб-страницы можно кешировать в памяти веб-сервера, заключив внутрь тегов
Продолжение следует…
Источник: Адам Фримен “Pro ASP.NET Core MVC 2”. – Диалектика, 2019. Глава 25.
ASP.NET Core. Тег-хелперы. Продолжение
4. Работа с файлами JS и CSS
Файлы JS и CSS на HTML страницу подключаются с помощью тегов
<script>
(класс ScriptTagHelper
) и <link>
(класс LinkTagHelper
) соответственно. Внутри них можно использовать тег-хелперы:asp-src-include
и asp-src-exclude
– включают/исключают файлы по шаблону локального пути. Таким образом можно включать, например, все файлы определённой библиотеки. В шаблонах можно использовать следующие знаки:?
– любой одиночный символ*
- любые символы, кроме /
(внутри одной папки)**
- любые символы, включая /
(включая подпапки)Кроме того, можно использовать несколько шаблонов через запятую.
Аналогично для файлов CSS используются
asp-href-include
и asp-href-exclude
. Например:<link rel="stylesheet"Включит все файлы из всех подпапок папки
asp-href-include="/lib/bootstrap/dist/**/*.min.css"
asp-href-exclude="**/*-reboot*,**/*-grid*" />
/lib/bootstrap/dist
, оканчивающиеся на .min.css
, но исключит файлы, содержащие в имени "-reboot
" или "-grid
". asp-append-version="true"
применяется для добавления версии к статическим файлам. Браузер кеширует статические файлы, поэтому применение версий позволяет изменять URL для запроса статического файла, тем самым обновляя файл на стороне клиента. Система ASP.NET автоматически отслеживает файлы на сервере и меняет номер добавляемой к URL версии, когда они изменяются. Аналогично версию можно применить к элементам img
.Группа тег-хелперов
asp-fallback
применяется, когда используются файлы JS и CSS из внешнего источника, например, сети доставки контента (CDN). Если по каким-то причинам внешний файл не может быть получен, можно использовать локальный файл с помощью атрибута asp-fallback-src
для JS и asp-fallback-href
для CSS. Также можно использовать asp-fallback-*-include
и asp-fallback-*-exclude
аналогично описанным выше.Для проверки, загрузился ли внешний файл, в JS используется тег-хелпер
asp-fallback-test
, содержащий JS код, например:<script … asp-fallback-test="window.jQuery">Если код вернёт ошибку, будет использован локальный файл.
Для CSS всё немного сложнее. Нужно использовать 3 свойства: имя класса CSS, свойство и значение. В разметку будет добавлен JS код, который проверит, соответствует ли значение заданного свойства заданного CSS-класса значению, указанному в тег-хелпере. Если нет (стили не были применены, т.к. файл не удалось загрузить), будет использован локальный файл. Например:
<link href="…" …5. Использование кэша
asp-fallback-test-class="btn"
asp-fallback-test-property="display"
asp-fallback-test-value="inline-block" />
Отдельные части веб-страницы можно кешировать в памяти веб-сервера, заключив внутрь тегов
<cache>…</cache>
, чтобы снизить нагрузку на сервер и время отклика веб-страницы. Поскольку размер памяти веб-сервера ограничен, кешированием можно управлять с помощью тег-хелперов:- enabled
– используется ли кэширование (по умолчанию true) - expires-*
– группа тег-хелперов для указания времени истечения срока кэширования: абсолютное (expires-on
), относительное (-after
), после последнего запроса (-sliding
).- vary-by-*
– группа тег-хелперов для указания вариативности кэша по маршруту (vary-by-route
), строке запроса (-query
), http-заголовку (-header
), значению куки (-cookie
), аутентифицированному пользователю (-user
) и т.п. - priority
– относительный приоритет кэша (при нехватке памяти кэш с меньшим приоритетом удаляется в первую очередь).Продолжение следует…
Источник: Адам Фримен “Pro ASP.NET Core MVC 2”. – Диалектика, 2019. Глава 25.
День четыреста восьмидесятый. #ЗаметкиНаПолях
ASP.NET Core. Тег-хелперы. Окончание
6. Регистрация тег-хелперов
Чтобы тег-хелперы применялись в представлении, их нужно зарегистрировать с помощью Razor-выражения
7. Создание тег-хелпера
Создать свой тег-хелпер можно, унаследовав от класса
Атрибут класса
- первый параметр – имя тега (если опущено, применяется ко всем тегам).
-
-
-
Атрибут можно использовать несколько раз, чтобы тег-хелпер применялся к разным html-элементам. Следующий атрибут указывает, что тег-хелпер применяется к тегам button, имеющим атрибуты, начинающиеся на
- назначить имя html-атрибута для привязки с помощью атрибута
- запретить получать данные из html-атрибутов с помощью атрибута
- установить контекст представления с помощью атрибута
- привязать свойства модели, задав тип свойства
Логика преобразований html-тегов помещается в переопределённый метод
1) контекст тег-хелпера (например, теги, к которым он применён).
2) объект
Следующий тег-хелпер:
ASP.NET Core. Тег-хелперы. Окончание
6. Регистрация тег-хелперов
Чтобы тег-хелперы применялись в представлении, их нужно зарегистрировать с помощью Razor-выражения
@addTagHelper
либо в каждом отдельном представлении, либо в файле _ViewImports.cshtml
. Выражение принимает 2 параметра: имя классов тег-хелперов (можно использовать групповой символ *
) и имя сборки, где они определены:@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpersПодключит все классы тег-хелперов из стандартной сборки Microsoft.
7. Создание тег-хелпера
Создать свой тег-хелпер можно, унаследовав от класса
TagHelper
из пространства имен Microsoft.AspNetCore.Razor.TagHelpers
. Имя и свойства класса определяются соглашениями. Имя состоит из имени html-тега, к которому должен применяться тег-хелпер и суффикса TagHelper
. Имена свойств в стиле CamelCase получают значения от соответствующих атрибутов html-тега в стандартном стиле с разделителями дефисами. Например:public class ButtonTagHelper : TagHelperЭтот тег-хелпер будет применяться к элементам
public string BgStyle { get; set; }
…
}
<button>
, а свойству BgStyle
будет установлено значение атрибута bg-style="…"
. Это поведение можно изменить.Атрибут класса
HtmlTargetElement
определяет, к каким тегам применяется тег-хелпер. Параметры:- первый параметр – имя тега (если опущено, применяется ко всем тегам).
-
Attributes
– атрибуты, которые должен иметь html-тег. Можно указывать через запятую или использовать групповой символ *
.-
ParentTag
– имя родительского тега.-
TagStructure
– структура тега (имеет ли закрывающий тег).Атрибут можно использовать несколько раз, чтобы тег-хелпер применялся к разным html-элементам. Следующий атрибут указывает, что тег-хелпер применяется к тегам button, имеющим атрибуты, начинающиеся на
bs-button-
, и расположенным внутри элемента form
:[HtmlTargetElement("button", Attributes = "bs-button-*", ParentTag = "form")]Свойствам тег-хелпера можно:
- назначить имя html-атрибута для привязки с помощью атрибута
HtmlAttributeName
;- запретить получать данные из html-атрибутов с помощью атрибута
HtmlAttributesNotBound
;- установить контекст представления с помощью атрибута
ViewContext
(например, для получения данных о текущем контроллере или действии);- привязать свойства модели, задав тип свойства
ModelExpression
и передав html-атрибуту имя свойства модели.Логика преобразований html-тегов помещается в переопределённый метод
Process
, которому передаются:1) контекст тег-хелпера (например, теги, к которым он применён).
2) объект
TagHelperOutput
, содержащий свойства для управления результатом вывода.Следующий тег-хелпер:
public class ButtonTagHelper : TagHelperбудет применён ко всем тегам
public string BtnType { get; set; }
public override void Process(
TagHelperContext context,
TagHelperOutput output)
{
output.TagName = "button";
output.TagMode = TagMode.StartTagAndEndTag;
output.Attributes.SetAttribute(
"class", "btn btn-primary");
output.Attributes.SetAttribute(
"type", BtnType.ToLower());
output.Content.SetContent(BtnType);
}
}
button
. Например: <button btn-type="Submit" />Преобразуется в:
<button class="btn btn-primary" type="submit">Submit</button>Источник: Адам Фримен “Pro ASP.NET Core MVC 2”. – Диалектика, 2019. Глава 23.
День четыреста восемьдесят первый. #ЧтоНовенького
Топ Новостей с Конференции Microsoft Build 2020
1. Поддержка ASP.NET Blazor Web Assembly
Теперь есть возможность разрабатывать клиентские приложения, используя C#. Отпала необходимость в плагине, потому что эта технология теперь использует стандарт WebAssembly, позволяющий выполнять нативный код .NET прямо в браузере.
2. Мульти-платформенный UI Приложений (.NET MAUI)
Вместе с .NET 6. Microsoft представит технологию создания UI приложений для любого устройства (как настольного, так и мобильного) и любых операционных систем из единой кодовой базы. Превью ожидаются в конце года.
3. Превью C# 9 и .NET 5
Выпуск .NET 5 запланирован на ноябрь 2020 года. Все новые функции C# 9 будут также выпущены с .NET 5!
4. Улучшения в Visual Studio Live Share
Visual Studio Live Share теперь поддерживает текст, голосовой чат, а также предоставляет доступ к запущенным приложениям. Это позволит разработчикам сотрудничать без необходимости использования внешних приложений для совместного использования экрана.
5. Выпущен Windows Terminal
Windows Terminal позволяет запускать любое приложение командной строки внутри вкладок и панелей, а также имеет множество других возможностей кастомизации.
6. Представлена Project Reunion
Единая, более гибкая, современная и открытая платформа для разработчиков под Windows.
7. Learn TV
Learn TV объединяет контент из разных каналов Microsoft в единое пространство. Это место, где можно найти актуальный контент, чтобы всегда быть в курсе последних объявлений, функций и продуктов корпорации Майкрософт.
8. Множество Обновлений Azure
- Возможность встроить сценарии развертывания (powershell или bash) в шаблоны ARM для сквозной настройки среды.
- Новые возможности для баз данных PostgreSQL и MySQL.
- Более эффективное использование Cosmos DB.
- Поддержка Azure Kubernetes Service (AKS) для контейнеров Windows Server и многое другое.
Источник: https://www.productivecsharp.com/2020/05/top-csharp-news-microsoft-build-2020/
Топ Новостей с Конференции Microsoft Build 2020
1. Поддержка ASP.NET Blazor Web Assembly
Теперь есть возможность разрабатывать клиентские приложения, используя C#. Отпала необходимость в плагине, потому что эта технология теперь использует стандарт WebAssembly, позволяющий выполнять нативный код .NET прямо в браузере.
2. Мульти-платформенный UI Приложений (.NET MAUI)
Вместе с .NET 6. Microsoft представит технологию создания UI приложений для любого устройства (как настольного, так и мобильного) и любых операционных систем из единой кодовой базы. Превью ожидаются в конце года.
3. Превью C# 9 и .NET 5
Выпуск .NET 5 запланирован на ноябрь 2020 года. Все новые функции C# 9 будут также выпущены с .NET 5!
4. Улучшения в Visual Studio Live Share
Visual Studio Live Share теперь поддерживает текст, голосовой чат, а также предоставляет доступ к запущенным приложениям. Это позволит разработчикам сотрудничать без необходимости использования внешних приложений для совместного использования экрана.
5. Выпущен Windows Terminal
Windows Terminal позволяет запускать любое приложение командной строки внутри вкладок и панелей, а также имеет множество других возможностей кастомизации.
6. Представлена Project Reunion
Единая, более гибкая, современная и открытая платформа для разработчиков под Windows.
7. Learn TV
Learn TV объединяет контент из разных каналов Microsoft в единое пространство. Это место, где можно найти актуальный контент, чтобы всегда быть в курсе последних объявлений, функций и продуктов корпорации Майкрософт.
8. Множество Обновлений Azure
- Возможность встроить сценарии развертывания (powershell или bash) в шаблоны ARM для сквозной настройки среды.
- Новые возможности для баз данных PostgreSQL и MySQL.
- Более эффективное использование Cosmos DB.
- Поддержка Azure Kubernetes Service (AKS) для контейнеров Windows Server и многое другое.
Источник: https://www.productivecsharp.com/2020/05/top-csharp-news-microsoft-build-2020/
День четыреста восемьдесят второй. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
42. Держите Сборки в Чистоте
Вы периодически поглядываете на список предупреждений компилятора длиной в небольшой роман о плохом программировании и думаете: «Да, надо бы действительно что-то с этим сделать… но сейчас нет времени»? Или вы исправляете первое же предупреждение, которое появилось в сборке?
Когда начинаешь новый проект с нуля, нет ни предупреждений, ни беспорядка, ни проблем. Но по мере роста кодовой базы, если не обращать на это внимания, начинают накапливаться ошибки, предупреждения и прочие проблемы. Когда вокруг много шума, гораздо труднее найти действительно важное предупреждение.
Чтобы предупреждения снова стали полезными, я стараюсь использовать политику нулевой терпимости к предупреждениям в сборке. Даже если предупреждение не важно, я разбираюсь с ним. Если оно не критично, но актуально, я исправлю его. Если компилятор предупреждает о возможной пустой ссылке, я устраняю причину, даже если я «знаю», что проблема никогда не проявится при работе. Если во встроенной документации упоминаются параметры, которые были удалены или переименованы, я чищу документацию.
Если это предупреждение для меня действительно не важно, я спрашиваю команду, можем ли мы изменить нашу политику предупреждений. Например, я обнаружил, что документирование параметров и возвращаемого значения метода во многих случаях не имеет смысла, поэтому не должно возникать предупреждений, если документация отсутствует. Также обновление версии языка программирования может привести к тому, что код, который раньше был в порядке, теперь выдаёт предупреждения. Эти предупреждения меня не интересуют (по крайней мере, пока). А наличие кучи необязательных предупреждений не приносит пользы никому.
Поддержание чистой сборки помогает в том, что не приходится решать, имеет ли смысл каждое предупреждение, с которым я сталкиваюсь. Игнорирование чего-либо – это тоже умственная работа. Нужно избавляться от всей ненужной умственной работы, насколько это возможно. Чистая сборка также помогает тому, кто будет работать с моим кодом. Если я оставлю предупреждения, этому человеку также придётся разбираться, что актуально, а что нет. Но скорее всего этот человек просто проигнорирует все предупреждения, в том числе важные.
Предупреждения в сборке полезны. Просто нужно избавиться от шума, чтобы начать замечать их. Это не генеральная уборка кода. Просто, когда появляется что-то, чего вы не хотите видеть, немедленно разберитесь с этим одним из следующих способов:
- исправьте источник предупреждения,
- подавите этот вид предупреждений,
- настройте политики предупреждений в вашей IDE.
Поддержание чистоты сборки — это не только предотвращение ошибок компиляции или неудачных тестов: предупреждения также являются важной частью гигиены кода.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Johannes Brodwall
97 Вещей, Которые Должен Знать Каждый Программист
42. Держите Сборки в Чистоте
Вы периодически поглядываете на список предупреждений компилятора длиной в небольшой роман о плохом программировании и думаете: «Да, надо бы действительно что-то с этим сделать… но сейчас нет времени»? Или вы исправляете первое же предупреждение, которое появилось в сборке?
Когда начинаешь новый проект с нуля, нет ни предупреждений, ни беспорядка, ни проблем. Но по мере роста кодовой базы, если не обращать на это внимания, начинают накапливаться ошибки, предупреждения и прочие проблемы. Когда вокруг много шума, гораздо труднее найти действительно важное предупреждение.
Чтобы предупреждения снова стали полезными, я стараюсь использовать политику нулевой терпимости к предупреждениям в сборке. Даже если предупреждение не важно, я разбираюсь с ним. Если оно не критично, но актуально, я исправлю его. Если компилятор предупреждает о возможной пустой ссылке, я устраняю причину, даже если я «знаю», что проблема никогда не проявится при работе. Если во встроенной документации упоминаются параметры, которые были удалены или переименованы, я чищу документацию.
Если это предупреждение для меня действительно не важно, я спрашиваю команду, можем ли мы изменить нашу политику предупреждений. Например, я обнаружил, что документирование параметров и возвращаемого значения метода во многих случаях не имеет смысла, поэтому не должно возникать предупреждений, если документация отсутствует. Также обновление версии языка программирования может привести к тому, что код, который раньше был в порядке, теперь выдаёт предупреждения. Эти предупреждения меня не интересуют (по крайней мере, пока). А наличие кучи необязательных предупреждений не приносит пользы никому.
Поддержание чистой сборки помогает в том, что не приходится решать, имеет ли смысл каждое предупреждение, с которым я сталкиваюсь. Игнорирование чего-либо – это тоже умственная работа. Нужно избавляться от всей ненужной умственной работы, насколько это возможно. Чистая сборка также помогает тому, кто будет работать с моим кодом. Если я оставлю предупреждения, этому человеку также придётся разбираться, что актуально, а что нет. Но скорее всего этот человек просто проигнорирует все предупреждения, в том числе важные.
Предупреждения в сборке полезны. Просто нужно избавиться от шума, чтобы начать замечать их. Это не генеральная уборка кода. Просто, когда появляется что-то, чего вы не хотите видеть, немедленно разберитесь с этим одним из следующих способов:
- исправьте источник предупреждения,
- подавите этот вид предупреждений,
- настройте политики предупреждений в вашей IDE.
Поддержание чистоты сборки — это не только предотвращение ошибок компиляции или неудачных тестов: предупреждения также являются важной частью гигиены кода.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Johannes Brodwall