.NET Разработчик
6.51K subscribers
427 photos
2 videos
14 files
2.04K links
Дневник сертифицированного .NET разработчика.

Для связи: @SBenzenko

Поддержать канал:
- https://boosty.to/netdeveloperdiary
- https://patreon.com/user?u=52551826
- https://pay.cloudtips.ru/p/70df3b3b
Download Telegram
День двести девяносто второй.
Сертификат Microsoft. Экзамен 70-486. Шаг первый
Итак, как я уже писал выше, я нацелился на сертификат «Microsoft® Certified Solutions Associate: Web Applications». Таким образом, мне нужно сдать ещё один экзамен «Developing ASP.NET MVC Web Applications».
Что можно сказать при беглом осмотре описания:
1. Список тем кажется гораздо обширнее, чем по языку C# (хотя и там было не мало).
2. Похоже, нужно изучить как Framework, так и Core, более того знать отличия.
3. Какое-то нереальное количество вопросов по Azure.
4. В отличие от языка C#, источников информации крайне мало. По крайней мере, из того, что мне удалось найти, три с половиной книги по ASP.NET MVC и пара видеокурсов на Pluralsight (с платной подпиской) по Azure. Это, конечно, не считая предлагаемых очных 5-дневных (sic!!!) курсов за 30-40 т.р. Чему там за 5 дней могут научить, решительно непонятно. Судя по программе курса на одном из сайтов, они там просто идут по книге Адама Фримена «ASP.NET MVC с примерами на C#», что составляет процентов 20 от списка тем экзамена.

В общем, пока перспективы не сильно радужные, подбираю книги по MVC, с Azure буду разбираться потом.

UPD: Немного покопавшись на сайте MSDN Channel 9, где был видеокурс для подготовки к экзамену по C#, нашёл аналогичный курс по ASP.NET MVC.
День двести девяносто третий. #ЗаметкиНаПолях
Объявление структур только для чтения (C#7.2)
C# долгое время неявно копировал структуры. Все это задокументировано в спецификации. Причина, по которой компилятор делает эту копию, состоит в том, чтобы избежать изменения поля, доступного только для чтения, кодом в свойстве (или методом, если вы его вызываете). Смысл поля только для чтения состоит в том, что ничто не может изменить его значение. Было бы странно, если бы readOnlyField.SomeMethod() мог изменять поле. C# рассчитан на то, что любые мутаторы (set) свойств будут изменять данные, поэтому они запрещены для полей только для чтения. Но даже аксессор (get) свойства может попытаться изменить значение. Поэтому скрытая копия - это эффективная мера безопасности.
Но что, если структура может пообещать, что она этого не сделает? В конце концов, большинство структур разработано, чтобы быть неизменяемыми. В C#7.2 вы можете применить модификатор readonly к объявлению структуры, чтобы это сделать:
public readonly struct YearMonthDay
{
public int Year { get; }
public int Month { get; }
public int Day { get; }
public YearMonthDay(int year, int month, int day) =>
(Year, Month, Day) = (year, month, day);
}
Вы можете применять модификатор только в том случае, если ваша структура действительно доступна только для чтения и поэтому соответствует следующим условиям:
1. Каждое поле и автоматически реализованное свойство экземпляра должны быть доступны только для чтения. Статические поля и свойства все ещё могут быть доступны для чтения и записи.
2. Вы можете обращаться к this только внутри конструкторов. Можно рассматривать this в структурах:
- как out-параметр в конструкторах (инициализирует поле);
- как ref-параметр в членах обычных структур (изменяет значение поля по ссылке);
- как in-параметр в членах структур только для чтения (читает значение поля по ссылке).

Там, где вы можете сделать свои пользовательские структуры доступными только для чтения, я призываю вас сделать это. Просто помните, что это одностороннее изменение для публичного кода. Вы можете безопасно удалить модификатор позже, только если у вас есть возможность перекомпилировать весь код, который использует эту структуру.

Источник: Jon Skeet “C# In Depth”. 4th ed – Manning Publications Co, 2019. Глава 13.
День двести девяносто четвёртый. #ЗаметкиНаПолях
Больше возможностей передачи по ссылке. Продолжение
Методы расширения с ref или in параметрами (C#7.2)
Предположим, у вас есть большая структура, которую вы не хотите копировать, и метод, который вычисляет результат на основе значений свойств этой структуры (например, длину трехмерного вектора). Хорошо, если структура предоставляет сам метод (или свойство), особенно когда она объявлена с модификатором readonly. Вы можете избежать копирования без проблем. Но, возможно, вы делаете что-то более сложное, что авторы структуры не предусмотрели. Рассмотрим структуру Vector3D только для чтения со свойствами X, Y и Z:
public readonly struct Vector3D
{
public double X { get; }
public double Y { get; }
public double Z { get; }
public Vector3D(double x, double y, double z)
{ X = x; Y = y; Z = z; }
}
Можно написать метод, принимающий структуру с параметром in, но это будет выглядеть не слишком красиво:
double magnitude = VectorUtilities.Magnitude(vector);
Есть методы расширения, но обычный метод расширения, подобный этому, будет копировать вектор при каждом вызове:
public static double Magnitude(this Vector3D vector)
Неприятно выбирать между производительностью и удобочитаемостью.
В C#7.2 вы можете написать методы расширения с модификатором ref или in для первого параметра. Модификатор может идти до или после this. Если выполняется только чтение значений, используйте in, если значения изменяются, то ref:
public static double Magnitude(this in Vector3D vec) => 
Math.Sqrt(vec.X * vec.X + vec.Y * vec.Y + vec.Z * vec.Z);
public static void OffsetBy(this ref Vector3D orig, in Vector3D off) =>
orig = new Vector3D(orig.X + off.X, orig.Y + off.Y, orig.Z + off.Z);
Заметьте, что второй параметр в методе OffsetBy является параметром in. Мы максимально пытаемся избежать копирования.
Использовать методы расширения просто. Единственный, возможно, удивительный аспект заключается в том, что в отличие от обычных параметров ref, при вызове методов расширения с такими параметрами о них нет никакого упоминания:
var vector = new Vector3D(1.5, 2.0, 3.0);
var offset = new Vector3D(5.0, 2.5, -1.0);
vector.OffsetBy(offset);
Console.WriteLine($"({vector.X}, {vector.Y}, {vector.Z})");
Console.WriteLine(vector.Magnitude());
Вывод:
(6.5, 4.5, 2)
8.15475321515004
Вызов OffsetBy изменил переменную vector, как и предполагалось. Таким образом, метод OffsetBy делает нашу неизменяемую структуру Vector3D в некотором роде изменяемой. Этот функционал новый и лучших практик использования ещё не выведено, поэтому параметры ref пока стоит использовать с осторожностью.

Источник: Jon Skeet “C# In Depth”. 4th ed – Manning Publications Co, 2019. Глава 13.
This media is not supported in your browser
VIEW IN TELEGRAM
День двести девяносто пятый. #Оффтоп #МоиИнструменты
Object Exporter
В рабочем проекте логгер ошибок выкладывает сериализованные в JSON объекты в лог при возникновении ошибок. Возникла потребность сравнить состояние объекта из лога и состояние объекта в точке останова при дебаге. Начал копаться и нашёл расширение Object Exporter для Visual Studio. Он позволяет экспортировать объекты во время дебага и сериализовать их в код C# или в JSON или XML.
Варианты использования:
- Как описано выше, сравнение состояния объекта при дебаге.
- Поиск информации внутри объекта.
- Генерация инициализаторов объектов для юнит-тестов (сериализация в C#).
Судя по отзывам, есть несколько мелких косяков: давно не было обновлений, относительно медленная работа и (с чем я сам столкнулся) при экспорте в JSON вложенные объекты почему-то экспортируются без имени. Но ничего лучше я не нашёл. Если есть другие варианты, буду рад услышать предложения в чате
День двести девяносто шестой. #BestPractices
Советы по сериализации. Начало
Сериализация - это процесс преобразования объекта в формат, который можно легко сохранить или перенести. Например, вы можете сериализовать объект, передать его через Интернет с помощью HTTP и десериализовать его на конечном компьютере. Подробнее о процессе сериализации можно почитать тут.
Различают три основных типа сериализации:
- Data Contract
- XML
- Времени выполнения (бинарная или SOAP)

⚠️ РАССМОТРИТЕ возможность сериализации при разработке новых типов.

Выбор правильной технологии сериализации
⚠️ РАССМОТРИТЕ поддержку сериализации Data Contract, если экземпляры вашего типа, возможно, потребуется сохранять или использовать в веб-сервисах.
⚠️ РАССМОТРИТЕ поддержку сериализации XML вместо или в дополнение к Data Contract, если вам нужен больший контроль над форматом XML, который создается при сериализации типа. Это может быть необходимо в некоторых сценариях взаимодействия, где необходимо использовать конструкции XML, которые не поддерживаются сериализацией Data Contract, например, для создания атрибутов XML.
⚠️ РАССМОТРИТЕ поддержку сериализации времени выполнения, если экземпляры вашего типа должны перемещаться через границы .NET Remoting.

Поддержка сериализации Data Contract
Типы могут поддерживать сериализацию Data Contract, применяя атрибуты DataContract к типу и DataMember к элементам (полям и свойствам) типа.
⚠️ РАССМОТРИТЕ возможность сделать члены вашего типа открытыми, если тип может использоваться в средах с частичным доверием. В среде с полным доверием сериализаторы Data Contract могут сериализовать и десериализовать непубличные типы и члены.
❗️ НЕОБХОДИМО использовать и аксессор (get), и мутатор (set) для всех свойств, имеющих атрибут DataMember. В .NET Framework 3.5 SP1 некоторые свойства коллекции могут быть доступны только для чтения. Если тип не будет использоваться в средах с частичным доверием, аксессор и мутатор могут быть закрытыми.
⚠️ РАССМОТРИТЕ использование обратных вызовов сериализации для инициализации десериализованных экземпляров. За редкими исключениями, при десериализации объектов конструкторы не вызываются. Следовательно, любая логика, которая выполняется во время обычного создания объекта, должна быть реализована в методе обратного вызова. Методы обратного вызова помечаются атрибутами OnSerializing, OnSerialized, OnDeserializing, OnDeserialized.
⚠️ РАССМОТРИТЕ использование атрибута KnownType, чтобы указать конкретные типы, которые следует использовать при десериализации графа сложного объекта.
❗️ НЕОБХОДИМО учитывать обратную и прямую совместимость при создании или изменении сериализуемых типов. Помните, что сериализованные потоки новых версий вашего типа могут быть десериализованы в старую версию типа, и наоборот. Учтите, что члены данных, даже закрытые и внутренние, не могут изменять свои имена, типы или даже порядок в новых версиях типа, если не будут приняты особые меры для сохранения контракта с использованием явных параметров атрибутов Data Contract. Проверьте совместимость сериализации при внесении изменений в сериализуемые типы. Попробуйте десериализовать новую версию в старую и наоборот.
⚠️ РАССМОТРИТЕ реализацию IExtensibleDataObject, чтобы разрешить циклический переход между различными версиями типа. Интерфейс позволяет сериализатору гарантировать, что никакие данные не будут потеряны во время такого перехода. Свойство IExtensibleDataObject.ExtensionData используется для хранения любых данных из будущей версии типа, которые неизвестны текущей версии, и не могут быть сохранены в текущей версии. Когда текущая версия впоследствии сериализуется и десериализуется в будущую версию, дополнительные данные будут доступны в сериализованном потоке.

Продолжение следует…

Источник:
https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/
День двести девяносто седьмой. #BestPractices
Советы по сериализации. Окончание

Поддержка XML-сериализации
Сериализация Data Contract является основной технологией сериализации в .NET Framework, но существуют сценарии, которые она не поддерживает. Например, она не даёт вам полного контроля над форматом XML, создаваемым или потребляемым сериализатором. Если требуется такой точный контроль, необходимо использовать сериализацию XML, и разработать типы с поддержкой этой технологии сериализации.
ИЗБЕГАЙТЕ разработки ваших типов специально для XML-сериализации, если только у вас нет веских оснований контролировать формат создаваемого XML. Эта технология сериализации была заменена сериализацией Data Contract, рассмотренной в предыдущем посте.
⚠️ РАССМОТРИТЕ реализацию интерфейса IXmlSerializable, если вы хотите получить больший контроль над форматом сериализованного XML, чем просто применение атрибутов XML-сериализации. Два метода интерфейса, ReadXml и WriteXml, позволяют полностью контролировать сериализованный поток XML. Вы также можете управлять схемой XML применяя атрибут XmlSchemaProvider.

Поддержка сериализации времени выполнения
Сериализация времени выполнения - это технология, используемая в .NET Remoting. Если вы думаете, что ваши типы будут транспортироваться с помощью .NET Remoting, вам необходимо убедиться, что они поддерживают сериализацию времени выполнения.
Базовая поддержка сериализации времени выполнения может быть обеспечена путем применения атрибута Serializable, а более сложные сценарии включают реализацию простого паттерна сериализации времени выполнения (реализуйте ISerializable и предоставьте конструктор сериализации).
⚠️ РАССМОТРИТЕ поддержку сериализации времени выполнения, если ваши типы будут использоваться в .NET Remoting. Например, пространство имен System.AddIn использует .NET Remoting, поэтому все типы, которыми обмениваются надстройки System.AddIn, должны поддерживать сериализацию времени выполнения.
⚠️ РАССМОТРИТЕ реализацию паттерна сериализации времени выполнения, если вы хотите полностью контролировать процесс сериализации. Например, преобразовывать данные по мере их сериализации или десериализации.Для этого нужно реализовать интерфейс ISerializable и предоставить специальный конструктор, который используется при десериализации объекта.
ИСПОЛЬЗУЙТЕ защищённый конструктор сериализации с двумя параметрами, как показано ниже:
[Serializable]
public class Person : ISerializable
{
protected Person(SerializationInfo info, StreamingContext context) {…}
}
❗️ НЕОБХОДИМО явно реализовать элементы ISerializable.
❗️ НЕОБХОДИМО применить атрибут SecurityPermission(SecurityAction.LinkDemand) к реализации ISerializable.GetObjectData. Это гарантирует, что только полностью доверенный код получит доступ к методу.

Источник: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/
День двести девяносто восьмой. #Оффтоп
Хорошая картинка, посвящённая дизайну, основанному на пользовательском опыте, (UX-driven design) из лекции Дино Эспозито на конференции DotNext. С точки зрения пользователя наш софт – это слой представления и чёрный ящик. Поэтому дизайн, основанный на пользовательском опыте, предполагает сначала выяснение, какой функционал требуется конечному пользователю, а только затем дизайн кнопок - триггеров операций в бэкэнде, который для пользователя представляет собой чёрный ящик. То, что в чёрном ящике, пользователя не волнует. Важны команды, которые он туда посылает и результаты, которые он из него получает. Когда есть согласие с пользователем относительно презентационного слоя, большинство проблем использования, обычно возникающих после релиза продукта, решаются на ранних этапах проектирования.
Полная лекция (на английском): https://youtu.be/xeMbZyhzoAw
День двести девяносто девятый. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
9. Сначала проверьте свой код, прежде чем обвинять других
Признайтесь, каждому из нас хоть раз было трудно признаться себе, что наш код не работает. Этого
просто не может быть! Это настолько невероятно, что наверняка именно в этот раз проблема должна
быть в компиляторе/фреймворке/библиотеке.
Но на самом деле это крайне – крайне! – маловероятно, что работа кода нарушается из-за ошибки в
компиляторе, интерпретаторе, ОС, сервере приложений, фреймворке, базе данных, диспетчере памяти или любом другом компоненте системного программного обеспечения. Да, эти ошибки существуют, но они встречаются гораздо реже, чем нам хотелось бы верить.
Однажды я в самом деле столкнулся с ошибкой компилятора, который при оптимизации выкидывал
переменную цикла, но грешил на ошибку в компиляторе или ОС я гораздо чаще. Я тратил много своего времени и времени техподдержки, только чтобы в итоге чувствовать себя идиотом каждый раз, когда в конце концов оказывалось, что ошибка была у меня.
Если инструмент широко распространён и используется множеством людей в различных ситуациях, то причин сомневаться в его качестве очень мало. Конечно, если это бета-версия инструмента или он используется всего несколькими людьми? или же это проект с открытым кодом на ранних стадиях разработки, могут быть веские основания подозревать его.
Но учитывая, насколько редки ошибки в компиляторах, вы гораздо лучше потратите своё время и энергию на поиск ошибки в своем коде, чем на доказательство того, что компилятор не прав. Применимы все обычные рекомендации по отладке.
Когда кто-то другой сообщает о проблеме, которую вы не можете воспроизвести, сходите и посмотрите, что он делает. Люди могут делать то, о чём вы никогда бы не подумали, или делать что-то в другом порядке.
Проблемы с многопоточностью также являются очень частым источником ошибок, заставляющим седеть и орать на компьютер. Все рекомендации в пользу написания простого кода становятся на порядок важнее, когда система многопоточная. При поиске таких ошибок нельзя уверенно полагаться на отладку и модульные тесты, поэтому простота проектирования имеет первостепенное значение.
Итак, прежде чем спешить обвинять компилятор, фреймворк или библиотеку вспомните совет Шерлока Холмса: «После того, как вы исключили невозможное, то всё, что осталось, независимо от того, насколько невероятным оно выглядит, является истиной», и отдавайте предпочтение именно ему, а не правилу Дирка Джентли: «После того, как вы исключили невероятное, всё, что осталось, независимо от того, насколько невозможным оно выглядит, является истиной».

Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Allan Kelly
День трёхсотый. #ВопросыНаСобеседовании
Юбилейный день – самое время начать новый тред)))
Самые часто задаваемые вопросы на собеседовании по ASP.NET MVC
1. Что такое MVC (Model-View-Controller)?
Модель–представление–контроллер (MVC) - это паттерн архитектуры ПО для разделения данных приложения, пользовательского интерфейса и управляющей логики на три отдельных компонента: модель, представление и контроллер — таким образом, что модификация каждого компонента может осуществляться независимо. ASP.NET MVC - это фреймворк для создания веб-приложений с использованием паттерна MVC.
Модель реализует бизнес-логику приложения. Объекты модели хранят данные модели и зачастую взаимодействуют с базой данных.
Представление реализует отображение данных. Чаще всего представления создаются на основе данных модели.
Контроллер обрабатывает взаимодействие с пользователем (запросы пользователя к страницам, либо данные, введённые пользователем в форму представления), взаимодействует с моделью (запрашивает или обновляет данные) и возвращает ответ (данные в представлении).
Разделение MVC помогает управлять сложными приложениями, потому что вы можете сосредоточиться на одной области за раз. Например, работать с представлением, не трогая бизнес-логику. Это также облегчает тестирование приложения. Кроме того, различные разработчики могут работать над представлением, логикой контроллера или бизнес-логикой параллельно.

Источник: https://www.c-sharpcorner.com
День триста первый. #Оффтоп
Затарился книжечками, чтобы не скучать в новом году)))
День триста второй. #юмор
Далёкое будущее уже не такое далёкое)))
👍1
День триста третий. #BestPractices
Операторы Равенства
Далее обсуждаются перегрузки операторов равенства (operator== и operator!=).

ИЗБЕГАЙТЕ перегрузки одного из операторов равенства без перегрузки другого.
❗️ НЕОБХОДИМО убедиться, что Object.Equals и операторы равенства имеют одинаковую семантику и схожие характеристики производительности. Чаще всего это означает, что необходимо переопределить Object.Equals, когда операторы равенства перегружены.
ИЗБЕГАЙТЕ выброса исключений из операторов равенства. Например, возвращайте false, если один из аргументов имеет значение null, а не выбрасывайте NullReferenceException.

Операторы равенства в значимых типах
ИСПОЛЬЗУЙТЕ перегрузку операторов равенства для значимых типов, если имеет смысл сравнивать объекты этого типа. В большинстве языков программирования отсутствует стандартная реализация operator== для значимых типов.

Операторы равенства в ссылочных типах
ИЗБЕГАЙТЕ перегрузки операторов равенства в изменяемых ссылочных типах. Многие языки имеют встроенные операторы равенства для ссылочных типов. Встроенные операторы обычно проверяют на равенство ссылки на объекты, и многие разработчики удивляются, когда поведение по умолчанию изменяется на проверку равенства значений. Эта проблема менее актуальна для неизменяемых ссылочных типов, потому что для неизменяемых типов разница между ссылочным равенством и равенством значений менее принципиальна.
ИЗБЕГАЙТЕ перегрузки операторов равенства в ссылочных типах, если реализация будет значительно медленнее, чем реализация ссылочного равенства.

Источник: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/
День триста четвёртый. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
10. Тщательно выбирайте инструменты

Современные приложения очень редко пишутся с чистого листа. Они собираются с использованием существующих инструментов - компонентов, библиотек и фреймворков - по ряду веских причин:
1. Приложения увеличиваются в размерах и сложности, а время, необходимое для их разработки, сокращается. Это позволяет лучше использовать время и интеллект разработчиков, если они смогут сконцентрироваться на написании большего количества кода бизнес-логики и меньшего количества кода инфраструктуры.
2. Широко используемые компоненты и структуры, вероятно, будут иметь меньше ошибок, чем разработанные самостоятельно.
3. В сети доступно много высококачественного бесплатного программного обеспечения, что означает более низкие затраты на разработку и большую вероятность поиска разработчиков с необходимым интересом и опытом.
4. Производство и обслуживание программного обеспечения - трудоёмкая работа, поэтому покупка готового решения может быть дешевле, чем разработка.

Тем не менее, выбор правильного набора инструментов для вашего приложения может быть сложной задачей, требующей обдумывания. Делая выбор, вы должны иметь в виду несколько вещей:
1. Различные инструменты могут полагаться на разные предположения о контексте их использования: окружающей инфраструктуре, модели управления, модели данных, протоколах связи и т.д. Это может привести к несоответствию архитектуры приложения и инструментов. Такое несоответствие приводит появлению костылей и обходных путей, которые сделают код более сложным, чем необходимо.
2. Различные инструменты имеют разные жизненные циклы, и обновление одного из них может стать чрезвычайно сложной и трудоемкой задачей, поскольку новые функциональные возможности, изменения дизайна или даже исправления ошибок могут привести к несовместимости с другими инструментами. Чем больше инструментов, тем острее может встать эта проблема.
3. Некоторые инструменты требуют небольшой настройки, часто с помощью одного или нескольких файлов конфигурации, что очень быстро может выйти из-под контроля. Приложение может выглядеть так, как если бы оно было написано из файлов конфигурации и нескольких странных строк кода на каком-то языке программирования. Сложность конфигурации делает приложение трудным в обслуживании и расширении.
4. Зависимость от поставщика наступает, когда ваш код активно использует продукты конкретного поставщика, что в конечном итоге накладывает ограничения на код в плане расширяемости, лёгкости изменения, производительности, стоимости сопровождения и т.д.
5. Если вы планируете использовать бесплатное программное обеспечение, вы можете обнаружить, что оно не так уж и бесплатно. Возможно, вам придётся купить коммерческую поддержку, которая не обязательно будет дешёвой. Условия лицензирования имеют значение даже для свободного ПО. Например, в некоторых компаниях недопустимо использовать ПО с бесплатной лицензией GNU из-за его вирусной природы. То есть разработанное с использованием его ПО должно распространяться с открытым исходным кодом.

Моя стратегия по смягчению этих проблем - начать с малого, используя только те инструменты, которые абсолютно необходимы. Обычно первоначальный акцент делается на устранении необходимости участвовать в низкоуровневом программировании инфраструктуры, например, с использованием некоторого промежуточного программного обеспечения вместо использования сокетов напрямую для распределённых приложений. А затем можно добавлять новые слои, если необходимо. Я также стремлюсь изолировать внешние инструменты от объектов моей бизнес-области с помощью интерфейсов и слоёв, чтобы при необходимости можно было заменить инструмент с минимальными затратами. Положительным побочным эффектом этого подхода является то, что я обычно получаю приложение меньшего размера, которое использует меньше внешних зависимостей, чем первоначально прогнозировалось.

Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Giovanni Asproni
День триста пятый. #Оффтоп
Нелёгкая судьба программиста занесла меня в окрестности Майами. Поэтому сегодня будет совсем оффтоп, т.к. из-за длинного перелёта пост написать не смог. В общем, всем доброго утра с берегов Атлантики.
День триста шестой. #МоиИнструменты
Качество кода. Начало
Улучшение кода может быть сложной задачей. Чем больше кодовая база, тем сложнее становится вручную находить и исправлять плохой код. Функции становятся более трудоемкими и рискованными для реализации, а ошибки возникают чаще. Стоимость обучения новых сотрудников также возрастает, потому что им требуется больше времени, чтобы понять, что делает код. Поиск путей улучшения качества кода крайне важен. Лучше всего учитывать качество кода изначально, но зачастую эта мысль приходит поздно. Однако плохо написанный код может со временем быть очищен.
Анализ кода и метрики являются отправной точкой для улучшения кодовой базы. Код - это данные, и есть инструменты его анализа. Однако в Visual Studio они практически отсутствуют, поэтому необходимы сторонние решения.
Что нужно знать о коде:
- объём кода
- соответствует ли он нашим стандартам кодирования
- наиболее подверженные ошибкам области кода
- какие части кода слишком сложны
- можно ли провести юнит-тестирование модуля
и так далее.

Resharper / Rider
JetBrains является лидером в области рефакторинга и анализа кода. Resharper помогает вам находить проблемный код и быстро его исправлять, в то время как Rider - это полноценная IDE, обладающая той же функциональностью. Resharper - самый популярный инструмент рефакторинга кода C#, который также анализирует HTML, XAML, JavaScript и многое другое.
Этот инструмент используется для получения метрик для проблемного кода. Вы можете просканировать один проект или всё решение. Это полезно, потому что помогает идентифицировать шаблоны в кодовой базе. Например, понять, что команда не знает о каких-то функциях C#, или что из раза в раз делает типичные ошибки.
Недостатком Resharper является то, что он раздувает IDE, добавляя пункты в меню и может нарушить обычную работу Visual Studio. Я отключаю его, когда не выполняю рефакторинг, и использую только тогда, когда пришло время очистить код. Некоторым нравится интерфейс Resharper, поэтому есть смысл приобрести IDE Rider и получить Resharper бесплатно.

NDepend
NDepend – фреймворк для анализа кода. Он имеет функционал, аналогичный Resharper, но более высокоуровневые инструменты. Его можно использовать как отдельное приложение или как расширение Visual Studio. Он также интегрируется с множеством других инструментов для предоставления дополнительной информации. Например, может интегрироваться с инструментами анализа покрытия кода тестами, такими как dotCover.
NDepend не просто анализирует ваш код. Он также измеряет изменение качества вашего кода с течением времени и показывает это на графике.
Кроме того, он может определить, какие типы в первую очередь подойдут для рефакторинга, исходя из срока технического долга.
Поначалу NDepend может показаться слишком сложным. Это комплексный инструмент, который требует некоторых усилий, чтобы понять его и подготовить ваше решение. Однако для крупных проектов он может предоставить то, чего не могут другие решения.

Автор: Christian Findlay
Источник:
https://christianfindlay.com/
День триста седьмой. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по ASP.NET MVC
2. Какие преимущества у MVC?

- Поддержка нескольких представлений
Благодаря отделению модели от представления пользовательский интерфейс может отображать несколько представлений одних и тех же данных одновременно.
- Простота изменений
Пользовательские интерфейсы, как правило, меняются чаще, чем бизнес-правила (цвета, шрифты, дизайн для разных видов устройств и т.п.). Поскольку модель не зависит от представления, добавление новых представлений в систему не влияет на модель. В результате область изменений ограничена представлением.
- Разделение Ответственности (Separation of Concerns - SoC)
Это одно из основных преимуществ ASP.NET MVC. Инфраструктура MVC обеспечивает четкое разделение пользовательского интерфейса, бизнес-логики, модели или данных.
- Больше контроля
Среда ASP.NET MVC обеспечивает больший контроль над HTML, JavaScript и CSS, чем традиционные веб-формы.
- Простота интеграции с Javascript фреймворками
MVC дает возможность лёгкой интеграции с Javascript библиотеками и фреймворками (например, jQuery, Angular и т.п.).
- Тестируемость
Фреймворк ASP.NET MVC обеспечивает лучшую тестируемость веб-приложения и хорошую поддержку для разработки на основе тестирования (TDD).
- Легковесность
Платформа ASP.NET MVC не использует View State и, таким образом, до некоторой степени снижает нагрузку на сеть.
- Полнота возможностей ASP.NET
Одним из ключевых преимуществ использования ASP.NET MVC является то, что он построен поверх платформы ASP.NET, и, следовательно, предоставляет доступ к большинству функций ASP.NET, таких как поставщики членства, ролей и т.д.

Источник: https://www.c-sharpcorner.com
День триста восьмой. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
11. Программируйте на языке предметной области
Представьте две программы. В одной вы видите:
if (portfolioIdsByTraderId.get(trader.getId())
.containsKey(portfolio.getId())) {...}
Вы чешете голову, гадая, для чего этот код может быть. Кажется, он получает идентификатор от объекта trader и использует его, чтобы получить объект portfolio из словаря, а затем проверяет, существует ли другой идентификатор объекта portfolio во внутреннем словаре. Вы, ещё немного почёсывая голову, ищите объявление portfolioIdsByTraderId и обнаруживаете это:
Map<int, Map<int, int>> portfolioIdsByTraderId;
Постепенно вы понимаете, что это может иметь какое-то отношение к тому, имеет ли трейдер доступ к определенному портфелю. И, конечно, вы встретите тот же код для проверки этого - или, что более вероятно, похожий, но слегка различающийся фрагмент кода - всякий раз, где требуется проверка, имеет ли трейдер доступ к определённому портфелю.
В другой программе вы видите это:
if (trader.canView(portfolio)) {...}
Всё понятно без объяснения. Вам не нужно знать, как объект trader это проверяет. Возможно, где-то внутри спрятана точно та же проверка в словаре из словарей. Но это дело объекта trader, а не ваше.
С какой из этих программ вы бы предпочли работать?
Когда-то у нас были только очень простые структуры данных: биты, байты и символы (на самом деле это тоже были байты, но мы притворялись, что это буквы и знаки пунктуации). С дробными числами было посложнее, потому что наши десятичные числа не очень хорошо работают в двоичном формате, поэтому у нас было несколько типов с плавающей точкой. Затем появились массивы и строки (на самом деле тоже массивы). Потом были стеки, очереди, хэшированные наборы, связанные списки и множество других интересных структур данных, которых не существует в реальном мире. Всё «программирование» состояло из попыток отобразить реальный мир в наших ограниченных структурах данных. Настоящие гуру могли даже вспомнить, как они это сделали.
Потом появились пользовательские типы! ОК, это не новость, но это немного меняет игру. Если ваш домен содержит такие понятия, как трейдеры и портфели, вы можете моделировать их с помощью таких типов, как, скажем, Trader и Portfolio. Но, что более важно, вы можете смоделировать отношения между ними, используя термины предметной области.
Если вы не программируете в терминах предметной области, вы создаёте молчаливое (читай: секретное) понимание того, что этот int здесь означает идентификатор трейдера, тогда как этот int означает идентификатор портфеля. (И лучше их не путать!) И если вы реализуете бизнес-концепцию «Некоторым трейдерам нельзя просматривать некоторые портфели, это незаконно» при помощи алгоритма, подобного поиску соответствия в таблице идентификаторов, то вы не даёте тем, кому придётся с этим разбираться, вообще никакой подсказки.
Следующий программист может не знать этого секрета, так почему бы не раскрыть его? Использование ключа для поиска другого ключа, который выполняет проверку существования, само по себе не очевидно. Как кто-то должен понять, что здесь применяются бизнес-правила, предотвращающие конфликт интересов?
Если в вашем коде явным образом изложены концепции предметной области, другие программисты смогут гораздо легче понять смысл кода, чем пытаясь встроить алгоритм в то, что они понимают в предметной области. Это также означает, что по мере развития предметной области (а она непременно будет изменяться и развиваться) вам легко будет изменять код. При грамотном использовании инкапсуляций велика вероятность того, что проверка, приведённая выше, будет существовать только в одном месте, и вы сможете изменить её в одном месте, не сломав зависимый код.
Программист, который будет работать с этим кодом через несколько месяцев, поблагодарит вас. Этим программистом вполне можете быть вы сами.

Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Dan North
День триста девятый. #Оффтоп
Важность алгоритмов
Часто встречаю вопрос: «Насколько важно знать алгоритмы, и какие нужно знать в первую очередь?» В принципе, конечно, неплохо хотя бы примерно представлять суть нескольких простейших алгоритмов. В конце концов, это, наверное, лучший способ проверить ваши когнитивные способности на собеседовании. Ну и конечно, если вы нацелились на низкоуровневую разработку, то тут без отличного знания алгоритмов не обойтись. Но в подавляющем большинстве случаев в практике ими пользоваться практически не придётся, т.к. все они уже реализованы в стандартных (и не очень) библиотеках. И гораздо более важную роль сейчас играет DDD (Domain Driven Development), то есть способность грамотно спроектировать предметную область. Это совсем не значит, что такие требования предъявляются только архитекторам или сеньорам. Проектирование отдельных классов и методов тоже немаловажная задача.
Вот тут Stefan Mischook подробнее рассуждает на эту тему.
This media is not supported in your browser
VIEW IN TELEGRAM
День триста десятый. #ЧтоНовенького
Новинки Visual Studio 2019 версии 16.4
В Microsoft объявили о релизе Visual Studio 2019 версии 16.4. Её можно скачать тут, либо обновить свою IDE из меню Help. Помимо функций, ранее описанных здесь и здесь, вот что ещё интересного приготовили ребята из Редмонда.
Закрепляемые Cвойства
Идентификация объектов по их свойствам при отладке стала проще и доступнее при помощи инструмента Закрепляемые Свойства. Наведите курсор на свойство, которое вы хотите отобразить в оконе Watch, Autos или Locals. Нажмите на значок булавки и вы увидите нужную информацию об объекте в столбце значения (см. картинку).
Команда Перехода к Базовому Классу
Добавлена команда Go To Base, для перемещения вверх по цепочке наследования. Она доступна во всплывающем меню при нажатии правой кнопки мыши, либо по горячим клавишам Alt+Home, когда курсор установлен на нужном элементе.

Источник: https://devblogs.microsoft.com/visualstudio/tis-the-season-visual-studio-2019/
День триста одиннадцатый. #DesignPatterns
Паттерны проектирования
1. Паттерн «Стратегия» (Strategy). Начало
Паттерн «Стратегия» является настолько распространенным и общепринятым, что многие его используют постоянно, даже не задумываясь об этом. Сортировка, анализ данных, валидация, разбор данных, сериализация, кодирование/декодирование, получение конфигурации — все эти концепции могут и должны быть выражены в виде стратегий или политик (policy).
Назначение: определяет семейство алгоритмов, инкапсулирует каждый из них и делает их взаимозаменяемыми. Стратегия позволяет изменять алгоритмы независимо от клиентов, которые ими пользуются.
Причины использования:
- необходимость инкапсуляции поведения или алгоритма;
- необходимость замены поведения или алгоритма во время исполнения.
Стратегия нужна тогда, когда не просто требуется спрятать алгоритм, а важно иметь возможность заменить его во время исполнения.
Классическая диаграмма приведена на рисунке ниже:
- Strategy — определяет интерфейс алгоритма;
- Context — клиент стратегии;
- ConcreteStrategyA, ConcreteStrategyB,… — конкретные реализации стратегии.
Классический паттерн весьма абстрактен. Он не определяет, каким образом контекст получает экземпляр стратегии, или как стратегия получит данные, необходимые для выполнения своей работы.

Выделение интерфейса
Существуют сторонники и противники выделения интерфейсов. Это относится не только к паттерну Стратегия. Обязательно ли выделять интерфейс AlgorithmInterface (см. рисунок ниже)? Это зависит от того, нужна ли нам стратегия и хотим ли мы заменять эту стратегию во время исполнения или можем использовать конкретную реализацию и внести в неё изменения в случае необходимости.
У выделения интерфейса и передачи его в качестве зависимости есть несколько особенностей. Передача интерфейса классу увеличивает гибкость, но в то же время повышает сложность. Теперь клиентам класса нужно либо решать, какую реализацию использовать, либо переложить эту ответственность на вызывающий код. Важно понимать, нужен ли дополнительный уровень абстракции именно сейчас. Может быть, на текущем этапе достаточно использовать класс напрямую, а выделить интерфейс только тогда, когда в этом действительно появится необходимость.

Продолжение следует…

Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 1.